Use roc_target over target_lexicon

Tailors a target class for our needs.
Replaces tons of uses across the entire compiler.
This is a base for later adding new targets like thumb.
This commit is contained in:
Brendan Hansknecht 2024-03-21 21:54:58 -07:00
parent 185262510c
commit 6dc5bfb1b7
No known key found for this signature in database
GPG key ID: 0EA784685083E75B
72 changed files with 1008 additions and 1371 deletions

View file

@ -8,6 +8,8 @@ license.workspace = true
version.workspace = true
[dependencies]
roc_error_macros = { path = "../../error_macros" }
strum.workspace = true
strum_macros.workspace = true
target-lexicon.workspace = true

View file

@ -3,70 +3,104 @@
// See github.com/roc-lang/roc/issues/800 for discussion of the large_enum_variant check.
#![allow(clippy::large_enum_variant)]
use strum_macros::{EnumCount, EnumIter, EnumString, IntoStaticStr};
use std::str::FromStr;
use roc_error_macros::user_error;
use strum_macros::{EnumCount, EnumIter};
use target_lexicon::Triple;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum OperatingSystem {
Freestanding,
Linux,
Mac,
Windows,
Unix,
Wasi,
}
impl OperatingSystem {
pub const fn new(target: target_lexicon::OperatingSystem) -> Option<Self> {
match target {
target_lexicon::OperatingSystem::Windows => Some(OperatingSystem::Windows),
target_lexicon::OperatingSystem::Wasi => Some(OperatingSystem::Wasi),
target_lexicon::OperatingSystem::Linux => Some(OperatingSystem::Unix),
target_lexicon::OperatingSystem::MacOSX { .. } => Some(OperatingSystem::Unix),
target_lexicon::OperatingSystem::Darwin => Some(OperatingSystem::Unix),
target_lexicon::OperatingSystem::Unknown => Some(OperatingSystem::Unix),
_ => None,
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PtrWidth {
Bytes4 = 4,
Bytes8 = 8,
}
pub const fn object_file_ext(&self) -> &str {
match self {
OperatingSystem::Windows => "obj",
OperatingSystem::Unix => "o",
OperatingSystem::Wasi => "wasm",
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, EnumIter, EnumCount)]
pub enum Architecture {
Aarch32,
Aarch64,
Wasm32,
X86_32,
X86_64,
}
pub const fn static_library_file_ext(&self) -> &str {
match self {
OperatingSystem::Windows => "lib",
OperatingSystem::Unix => "a",
OperatingSystem::Wasi => "wasm",
}
}
pub const fn executable_file_ext(&self) -> Option<&str> {
match self {
OperatingSystem::Windows => Some("exe"),
OperatingSystem::Unix => None,
OperatingSystem::Wasi => Some("wasm"),
}
impl std::fmt::Display for Architecture {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let arch_str = match self {
Architecture::Aarch32 => "aarch32",
Architecture::Aarch64 => "aarch64",
Architecture::Wasm32 => "wasm32",
Architecture::X86_32 => "x86_32",
Architecture::X86_64 => "x86_64",
};
write!(f, "{}", arch_str)
}
}
impl From<target_lexicon::OperatingSystem> for OperatingSystem {
fn from(target: target_lexicon::OperatingSystem) -> Self {
Self::new(target)
.unwrap_or_else(|| unreachable!("unsupported operating system {:?}", target))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TargetInfo {
pub architecture: Architecture,
pub operating_system: OperatingSystem,
}
impl TargetInfo {
impl Architecture {
pub const fn ptr_width(&self) -> PtrWidth {
self.architecture.ptr_width()
use Architecture::*;
match self {
X86_64 | Aarch64 => PtrWidth::Bytes8,
X86_32 | Aarch32 | Wasm32 => PtrWidth::Bytes4,
}
}
pub const fn ptr_alignment_bytes(&self) -> usize {
self.ptr_width() as usize
}
}
#[derive(Debug, Copy, Clone, EnumIter, PartialEq, Eq)]
pub enum Target {
LinuxX32,
LinuxX64,
LinuxArm64,
MacX64,
MacArm64,
WinX32,
WinX64,
WinArm64,
Wasm32,
}
impl Target {
pub const fn architecture(&self) -> Architecture {
use Target::*;
match self {
LinuxX32 | WinX32 => Architecture::X86_32,
LinuxX64 | WinX64 | MacX64 => Architecture::X86_64,
LinuxArm64 | WinArm64 | MacArm64 => Architecture::Aarch64,
Wasm32 => Architecture::Wasm32,
}
}
pub const fn operating_system(&self) -> OperatingSystem {
use Target::*;
match self {
LinuxX32 | LinuxX64 | LinuxArm64 => OperatingSystem::Linux,
MacX64 | MacArm64 => OperatingSystem::Mac,
WinX32 | WinX64 | WinArm64 => OperatingSystem::Windows,
Wasm32 => OperatingSystem::Freestanding,
}
}
pub const fn arch_os(&self) -> (Architecture, OperatingSystem) {
(self.architecture(), self.operating_system())
}
pub const fn ptr_width(&self) -> PtrWidth {
self.architecture().ptr_width()
}
pub const fn ptr_size(&self) -> usize {
@ -85,196 +119,177 @@ impl TargetInfo {
}
pub const fn ptr_alignment_bytes(&self) -> usize {
self.architecture.ptr_alignment_bytes()
self.architecture().ptr_alignment_bytes()
}
pub const fn default_aarch64() -> Self {
TargetInfo {
architecture: Architecture::Aarch64,
operating_system: OperatingSystem::Unix,
}
}
pub const fn default_x86_64() -> Self {
TargetInfo {
architecture: Architecture::X86_64,
operating_system: OperatingSystem::Unix,
}
}
pub const fn default_wasm32() -> Self {
TargetInfo {
architecture: Architecture::Wasm32,
operating_system: OperatingSystem::Wasi,
}
}
}
impl From<&target_lexicon::Triple> for TargetInfo {
fn from(triple: &target_lexicon::Triple) -> Self {
let architecture = Architecture::from(triple.architecture);
let operating_system = OperatingSystem::from(triple.operating_system);
Self {
architecture,
operating_system,
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PtrWidth {
Bytes4 = 4,
Bytes8 = 8,
}
/// These should be sorted alphabetically!
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, EnumIter, EnumCount)]
#[repr(u8)]
pub enum Architecture {
Aarch32,
Aarch64,
Wasm32,
X86_32,
X86_64,
}
impl Architecture {
pub const fn ptr_width(&self) -> PtrWidth {
use Architecture::*;
pub const fn object_file_ext(&self) -> &str {
use Target::*;
match self {
X86_64 | Aarch64 => PtrWidth::Bytes8,
X86_32 | Aarch32 | Wasm32 => PtrWidth::Bytes4,
LinuxX32 | LinuxX64 | LinuxArm64 | MacX64 | MacArm64 => "o",
WinX32 | WinX64 | WinArm64 => "obj",
Wasm32 => "wasm",
}
}
pub const fn ptr_alignment_bytes(&self) -> usize {
self.ptr_width() as usize
}
}
impl From<target_lexicon::Architecture> for Architecture {
fn from(target: target_lexicon::Architecture) -> Self {
match target {
target_lexicon::Architecture::X86_64 => Architecture::X86_64,
target_lexicon::Architecture::X86_32(_) => Architecture::X86_32,
target_lexicon::Architecture::Aarch64(_) => Architecture::Aarch64,
target_lexicon::Architecture::Arm(_) => Architecture::Aarch32,
target_lexicon::Architecture::Wasm32 => Architecture::Wasm32,
_ => unreachable!("unsupported architecture"),
}
}
}
#[derive(Debug, Copy, Clone, EnumIter, EnumString, IntoStaticStr, PartialEq, Eq, Default)]
pub enum Target {
#[strum(serialize = "system")]
#[default]
System,
#[strum(serialize = "linux-x32")]
LinuxX32,
#[strum(serialize = "linux-x64")]
LinuxX64,
#[strum(serialize = "linux-arm64")]
LinuxArm64,
#[strum(serialize = "macos-x64")]
MacX64,
#[strum(serialize = "macos-arm64")]
MacArm64,
#[strum(serialize = "windows-x32")]
WinX32,
#[strum(serialize = "windows-x64")]
WinX64,
#[strum(serialize = "windows-arm64")]
WinArm64,
#[strum(serialize = "wasm32")]
Wasm32,
}
const MACOS: target_lexicon::OperatingSystem = target_lexicon::OperatingSystem::MacOSX {
major: 12,
minor: 0,
patch: 0,
};
impl Target {
pub fn to_triple(self) -> Triple {
use target_lexicon::*;
pub const fn static_library_file_ext(&self) -> &str {
use Target::*;
match self {
Target::System => Triple::host(),
Target::LinuxX32 => Triple {
architecture: Architecture::X86_32(X86_32Architecture::I386),
vendor: Vendor::Unknown,
operating_system: OperatingSystem::Linux,
environment: Environment::Unknown,
binary_format: BinaryFormat::Elf,
},
Target::LinuxX64 => Triple {
architecture: Architecture::X86_64,
vendor: Vendor::Unknown,
operating_system: OperatingSystem::Linux,
environment: Environment::Unknown,
binary_format: BinaryFormat::Elf,
},
Target::LinuxArm64 => Triple {
architecture: Architecture::Aarch64(Aarch64Architecture::Aarch64),
vendor: Vendor::Unknown,
operating_system: OperatingSystem::Linux,
environment: Environment::Unknown,
binary_format: BinaryFormat::Elf,
},
Target::WinX32 => Triple {
architecture: Architecture::X86_32(X86_32Architecture::I386),
vendor: Vendor::Unknown,
operating_system: OperatingSystem::Windows,
environment: Environment::Gnu,
binary_format: BinaryFormat::Coff,
},
Target::WinX64 => Triple {
architecture: Architecture::X86_64,
vendor: Vendor::Unknown,
operating_system: OperatingSystem::Windows,
environment: Environment::Gnu,
binary_format: BinaryFormat::Coff,
},
Target::WinArm64 => Triple {
architecture: Architecture::Aarch64(Aarch64Architecture::Aarch64),
vendor: Vendor::Unknown,
operating_system: OperatingSystem::Windows,
environment: Environment::Gnu,
binary_format: BinaryFormat::Coff,
},
Target::MacX64 => Triple {
architecture: Architecture::X86_64,
vendor: Vendor::Apple,
operating_system: MACOS,
environment: Environment::Unknown,
binary_format: BinaryFormat::Macho,
},
Target::MacArm64 => Triple {
architecture: Architecture::Aarch64(Aarch64Architecture::Aarch64),
vendor: Vendor::Apple,
operating_system: MACOS,
environment: Environment::Unknown,
binary_format: BinaryFormat::Macho,
},
Target::Wasm32 => Triple {
architecture: Architecture::Wasm32,
vendor: Vendor::Unknown,
operating_system: OperatingSystem::Wasi,
environment: Environment::Unknown,
binary_format: BinaryFormat::Wasm,
},
LinuxX32 | LinuxX64 | LinuxArm64 | MacX64 | MacArm64 => "a",
WinX32 | WinX64 | WinArm64 => "lib",
Wasm32 => "wasm",
}
}
pub const fn executable_file_ext(&self) -> Option<&str> {
use Target::*;
match self {
LinuxX32 | LinuxX64 | LinuxArm64 | MacX64 | MacArm64 => None,
WinX32 | WinX64 | WinArm64 => Some("exe"),
Wasm32 => Some("wasm"),
}
}
}
impl From<&Target> for Triple {
pub enum ParseError {
InvalidTargetString,
}
impl FromStr for Target {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
use Target::*;
match s {
"system" => Ok(Self::default()),
"linux-x32" => Ok(LinuxX32),
"linux-x64" => Ok(LinuxX64),
"linux-arm64" => Ok(LinuxArm64),
// TODO: Can we change these to just `mac`.
// Currently, we need to keep it as `macos` to match platform naming.
"macos-x64" => Ok(MacX64),
"macos-arm64" => Ok(MacArm64),
"windows-x32" => Ok(WinX32),
"windows-x64" => Ok(WinX64),
"windows-arm64" => Ok(WinArm64),
"wasm32" => Ok(Wasm32),
_ => Err(ParseError::InvalidTargetString),
}
}
}
impl From<Target> for &'static str {
fn from(target: Target) -> Self {
Self::from(&target)
}
}
impl From<&Target> for &'static str {
fn from(target: &Target) -> Self {
target.to_triple()
use Target::*;
match target {
LinuxX32 => "linux-x32",
LinuxX64 => "linux-x64",
LinuxArm64 => "linux-arm64",
// TODO: Can we change these to just `mac`.
// Currently, we need to keep it as `macos` to match platform naming.
MacX64 => "macos-x64",
MacArm64 => "macos-arm64",
WinX32 => "windows-x32",
WinX64 => "windows-x64",
WinArm64 => "windows-arm64",
Wasm32 => "wasm32",
}
}
}
impl Default for Target {
fn default() -> Self {
Triple::host().into()
}
}
impl From<&Triple> for Target {
fn from(triple: &Triple) -> Self {
use target_lexicon::*;
match triple {
Triple {
architecture: Architecture::X86_32(_),
operating_system: OperatingSystem::Linux,
..
} => Target::LinuxX32,
Triple {
architecture: Architecture::X86_64,
operating_system: OperatingSystem::Linux,
..
} => Target::LinuxX64,
Triple {
architecture: Architecture::Aarch64(_),
operating_system: OperatingSystem::Linux,
..
} => Target::LinuxArm64,
Triple {
architecture: Architecture::X86_32(_),
operating_system: OperatingSystem::Windows,
..
} => Target::WinX32,
Triple {
architecture: Architecture::X86_64,
operating_system: OperatingSystem::Windows,
..
} => Target::WinX64,
Triple {
architecture: Architecture::Aarch64(_),
operating_system: OperatingSystem::Windows,
..
} => Target::WinArm64,
Triple {
architecture: Architecture::X86_64,
operating_system: OperatingSystem::MacOSX { .. } | OperatingSystem::Darwin,
..
} => Target::MacX64,
Triple {
architecture: Architecture::Aarch64(_),
operating_system: OperatingSystem::MacOSX { .. } | OperatingSystem::Darwin,
..
} => Target::MacArm64,
Triple {
architecture: Architecture::Wasm32,
..
} => Target::Wasm32,
_ => {
user_error!("Target triple ({}) is not currently supported by the roc compiler. Feel free to file an issue to request support", triple);
}
}
}
}
impl From<Triple> for Target {
fn from(triple: Triple) -> Self {
Target::from(&triple)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TargetFromTripleError {
TripleUnsupported,
}
impl TryFrom<(Architecture, OperatingSystem)> for Target {
type Error = TargetFromTripleError;
fn try_from(arch_os: (Architecture, OperatingSystem)) -> Result<Self, Self::Error> {
match arch_os {
(Architecture::X86_32, OperatingSystem::Linux) => Ok(Target::LinuxX32),
(Architecture::X86_64, OperatingSystem::Linux) => Ok(Target::LinuxX64),
(Architecture::Aarch64, OperatingSystem::Linux) => Ok(Target::LinuxArm64),
(Architecture::X86_32, OperatingSystem::Windows) => Ok(Target::WinX32),
(Architecture::X86_64, OperatingSystem::Windows) => Ok(Target::WinX64),
(Architecture::Aarch64, OperatingSystem::Windows) => Ok(Target::WinArm64),
(Architecture::X86_64, OperatingSystem::Mac) => Ok(Target::MacX64),
(Architecture::Aarch64, OperatingSystem::Mac) => Ok(Target::MacArm64),
(Architecture::Wasm32, _) => Ok(Target::Wasm32),
_ => Err(TargetFromTripleError::TripleUnsupported),
}
}
}
@ -283,48 +298,3 @@ impl std::fmt::Display for Target {
write!(f, "{}", Into::<&'static str>::into(self))
}
}
pub fn get_target_triple_str(target: &target_lexicon::Triple) -> Option<&'static str> {
match target {
target_lexicon::Triple {
architecture: target_lexicon::Architecture::Wasm32,
..
} => Some(Target::Wasm32.into()),
target_lexicon::Triple {
operating_system: target_lexicon::OperatingSystem::Linux,
architecture: target_lexicon::Architecture::X86_64,
..
} => Some(Target::LinuxX64.into()),
target_lexicon::Triple {
operating_system: target_lexicon::OperatingSystem::Linux,
architecture: target_lexicon::Architecture::Aarch64(_),
..
} => Some(Target::LinuxArm64.into()),
target_lexicon::Triple {
operating_system: target_lexicon::OperatingSystem::Darwin,
architecture: target_lexicon::Architecture::Aarch64(_),
..
} => Some(Target::MacArm64.into()),
target_lexicon::Triple {
operating_system: target_lexicon::OperatingSystem::Darwin,
architecture: target_lexicon::Architecture::X86_64,
..
} => Some(Target::MacX64.into()),
target_lexicon::Triple {
operating_system: target_lexicon::OperatingSystem::Windows,
architecture: target_lexicon::Architecture::X86_64,
..
} => Some(Target::WinX64.into()),
target_lexicon::Triple {
operating_system: target_lexicon::OperatingSystem::Windows,
architecture: target_lexicon::Architecture::X86_32(_),
..
} => Some(Target::WinX32.into()),
target_lexicon::Triple {
operating_system: target_lexicon::OperatingSystem::Windows,
architecture: target_lexicon::Architecture::Aarch64(_),
..
} => Some(Target::WinArm64.into()),
_ => None,
}
}