Skip to main content

lamina_codegen/
target_support.rs

1//! Cross-platform target support for code generation.
2//!
3//! This module defines which (architecture, OS) combinations are supported
4//! for assembly and binary emission, so callers can cross-compile to a
5//! different target than the host.
6
7use lamina_platform::{TargetArchitecture, TargetOperatingSystem};
8
9/// Returns true if assembly text generation is supported for this (arch, os).
10///
11/// Cross-compilation: pass the desired target, not the host.
12pub fn is_assembly_supported(arch: TargetArchitecture, os: TargetOperatingSystem) -> bool {
13    match arch {
14        TargetArchitecture::Nvptx64 => os == TargetOperatingSystem::Cuda,
15        TargetArchitecture::Amdgcn => os == TargetOperatingSystem::AmdHsa,
16        TargetArchitecture::X86_64 => os_supported_for_x86_64(os),
17        TargetArchitecture::Aarch64 => os_supported_for_aarch64(os),
18        TargetArchitecture::Arx64 => os_supported_for_arx64(os),
19        TargetArchitecture::Riscv32 | TargetArchitecture::Riscv64 => os_supported_for_riscv(os),
20        TargetArchitecture::Wasm32 | TargetArchitecture::Wasm64 => {
21            matches!(
22                os,
23                TargetOperatingSystem::Unknown | TargetOperatingSystem::Linux
24            )
25        }
26        _ => false,
27    }
28}
29
30/// Returns true if the OS is supported for x86_64 code generation.
31fn os_supported_for_x86_64(os: TargetOperatingSystem) -> bool {
32    matches!(
33        os,
34        TargetOperatingSystem::Linux
35            | TargetOperatingSystem::Android
36            | TargetOperatingSystem::MacOS
37            | TargetOperatingSystem::IOS
38            | TargetOperatingSystem::TvOS
39            | TargetOperatingSystem::WatchOS
40            | TargetOperatingSystem::VisionOS
41            | TargetOperatingSystem::Windows
42            | TargetOperatingSystem::FreeBSD
43            | TargetOperatingSystem::OpenBSD
44            | TargetOperatingSystem::NetBSD
45            | TargetOperatingSystem::DragonFly
46            | TargetOperatingSystem::Redox
47            | TargetOperatingSystem::Unknown
48    )
49}
50
51/// Returns true if the OS is supported for AArch64 code generation.
52fn os_supported_for_aarch64(os: TargetOperatingSystem) -> bool {
53    matches!(
54        os,
55        TargetOperatingSystem::Linux
56            | TargetOperatingSystem::Android
57            | TargetOperatingSystem::MacOS
58            | TargetOperatingSystem::IOS
59            | TargetOperatingSystem::TvOS
60            | TargetOperatingSystem::WatchOS
61            | TargetOperatingSystem::VisionOS
62            | TargetOperatingSystem::Windows
63            | TargetOperatingSystem::FreeBSD
64            | TargetOperatingSystem::OpenBSD
65            | TargetOperatingSystem::NetBSD
66            | TargetOperatingSystem::DragonFly
67            | TargetOperatingSystem::Redox
68            | TargetOperatingSystem::Unknown
69    )
70}
71
72/// Returns true if the OS is supported for ARX64 code generation.
73fn os_supported_for_arx64(os: TargetOperatingSystem) -> bool {
74    matches!(os, TargetOperatingSystem::Unknown)
75}
76
77/// Returns true if the OS is supported for RISC-V code generation.
78fn os_supported_for_riscv(os: TargetOperatingSystem) -> bool {
79    matches!(
80        os,
81        TargetOperatingSystem::Linux
82            | TargetOperatingSystem::FreeBSD
83            | TargetOperatingSystem::OpenBSD
84            | TargetOperatingSystem::NetBSD
85            | TargetOperatingSystem::DragonFly
86            | TargetOperatingSystem::Unknown
87    )
88}
89
90/// Returns a short description of supported targets for error messages.
91pub fn supported_assembly_targets_hint() -> &'static str {
92    "Supported: x86_64/aarch64/riscv32/riscv64/wasm32 on Linux, macOS, Windows, BSD, Redox \n and for bare-metal. Use lamina_platform::Target for cross-compilation."
93}
94
95/// Returns true if the given OS uses ELF object format (Linux, BSD, Redox, Horizon, Orbis, Prospero).
96pub fn os_uses_elf(os: TargetOperatingSystem) -> bool {
97    matches!(
98        os,
99        TargetOperatingSystem::Linux
100            | TargetOperatingSystem::Android
101            | TargetOperatingSystem::FreeBSD
102            | TargetOperatingSystem::OpenBSD
103            | TargetOperatingSystem::NetBSD
104            | TargetOperatingSystem::DragonFly
105            | TargetOperatingSystem::Redox
106            | TargetOperatingSystem::Horizon
107            | TargetOperatingSystem::Orbis
108            | TargetOperatingSystem::Prospero
109    )
110}
111
112/// Returns true if the given OS uses Mach-O (macOS).
113pub fn os_uses_macho(os: TargetOperatingSystem) -> bool {
114    matches!(
115        os,
116        TargetOperatingSystem::MacOS
117            | TargetOperatingSystem::IOS
118            | TargetOperatingSystem::TvOS
119            | TargetOperatingSystem::WatchOS
120            | TargetOperatingSystem::VisionOS
121    )
122}
123
124/// Returns true if the given OS uses COFF/PE (Windows).
125pub fn os_uses_coff(os: TargetOperatingSystem) -> bool {
126    os == TargetOperatingSystem::Windows
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    #[test]
134    fn test_x86_64_cross_platform() {
135        assert!(is_assembly_supported(
136            TargetArchitecture::X86_64,
137            TargetOperatingSystem::Linux
138        ));
139        assert!(is_assembly_supported(
140            TargetArchitecture::X86_64,
141            TargetOperatingSystem::Windows
142        ));
143        assert!(is_assembly_supported(
144            TargetArchitecture::X86_64,
145            TargetOperatingSystem::MacOS
146        ));
147        assert!(is_assembly_supported(
148            TargetArchitecture::X86_64,
149            TargetOperatingSystem::FreeBSD
150        ));
151    }
152
153    #[test]
154    fn test_aarch64_cross_platform() {
155        assert!(is_assembly_supported(
156            TargetArchitecture::Aarch64,
157            TargetOperatingSystem::Linux
158        ));
159        assert!(is_assembly_supported(
160            TargetArchitecture::Aarch64,
161            TargetOperatingSystem::MacOS
162        ));
163    }
164
165    #[test]
166    fn test_riscv_elf_like_only() {
167        assert!(is_assembly_supported(
168            TargetArchitecture::Riscv64,
169            TargetOperatingSystem::Linux
170        ));
171        assert!(!is_assembly_supported(
172            TargetArchitecture::Riscv64,
173            TargetOperatingSystem::Windows
174        ));
175    }
176
177    #[test]
178    fn test_wasm_limited_os() {
179        assert!(is_assembly_supported(
180            TargetArchitecture::Wasm32,
181            TargetOperatingSystem::Unknown
182        ));
183    }
184
185    #[test]
186    fn test_unknown_os_fallback() {
187        assert!(is_assembly_supported(
188            TargetArchitecture::X86_64,
189            TargetOperatingSystem::Unknown
190        ));
191        assert!(is_assembly_supported(
192            TargetArchitecture::Aarch64,
193            TargetOperatingSystem::Unknown
194        ));
195    }
196
197    #[test]
198    fn test_apple_mobile_assembly_supported() {
199        for os in [
200            TargetOperatingSystem::IOS,
201            TargetOperatingSystem::TvOS,
202            TargetOperatingSystem::WatchOS,
203            TargetOperatingSystem::VisionOS,
204        ] {
205            assert!(
206                is_assembly_supported(TargetArchitecture::X86_64, os),
207                "{os}"
208            );
209            assert!(
210                is_assembly_supported(TargetArchitecture::Aarch64, os),
211                "{os}"
212            );
213        }
214    }
215
216    #[test]
217    fn test_android_is_elf_and_assembly_supported() {
218        assert!(is_assembly_supported(
219            TargetArchitecture::X86_64,
220            TargetOperatingSystem::Android
221        ));
222        assert!(is_assembly_supported(
223            TargetArchitecture::Aarch64,
224            TargetOperatingSystem::Android
225        ));
226        assert!(os_uses_elf(TargetOperatingSystem::Android));
227    }
228
229    #[test]
230    fn test_apple_mobile_oses_use_macho() {
231        for os in [
232            TargetOperatingSystem::IOS,
233            TargetOperatingSystem::TvOS,
234            TargetOperatingSystem::WatchOS,
235            TargetOperatingSystem::VisionOS,
236        ] {
237            assert!(os_uses_macho(os), "{os} should use Mach-O");
238            assert!(!os_uses_elf(os), "{os} should not use ELF");
239        }
240    }
241
242    #[test]
243    fn test_unsupported_arch() {
244        assert!(!is_assembly_supported(
245            TargetArchitecture::Unknown,
246            TargetOperatingSystem::Linux
247        ));
248    }
249
250    #[test]
251    fn test_os_uses_elf() {
252        assert!(os_uses_elf(TargetOperatingSystem::Linux));
253        assert!(os_uses_elf(TargetOperatingSystem::FreeBSD));
254        assert!(os_uses_elf(TargetOperatingSystem::Redox));
255        assert!(os_uses_elf(TargetOperatingSystem::Horizon));
256        assert!(os_uses_elf(TargetOperatingSystem::Orbis));
257        assert!(os_uses_elf(TargetOperatingSystem::Prospero));
258        assert!(!os_uses_elf(TargetOperatingSystem::MacOS));
259        assert!(!os_uses_elf(TargetOperatingSystem::Windows));
260    }
261}