Skip to content

Commit

Permalink
feat: proper detection of archspec
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Mar 30, 2024
1 parent 103482e commit 6f95c44
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 18 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ lto = true

[workspace.dependencies]
anyhow = "1.0.80"
archspec = "0.1.2"
assert_matches = "1.5.0"
async-compression = { version = "0.4.6", features = [
"gzip",
Expand Down
1 change: 1 addition & 0 deletions crates/rattler-bin/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod create;
pub mod virtual_packages;
12 changes: 12 additions & 0 deletions crates/rattler-bin/src/commands/virtual_packages.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use rattler_conda_types::GenericVirtualPackage;

#[derive(Debug, clap::Parser)]
pub struct Opt {}

pub fn virtual_packages(_opt: Opt) -> anyhow::Result<()> {
let virtual_packages = rattler_virtual_packages::VirtualPackage::current()?;
for package in virtual_packages {
println!("{}", GenericVirtualPackage::from(package.clone()));
}
Ok(())
}
2 changes: 2 additions & 0 deletions crates/rattler-bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct Opt {
#[derive(Debug, clap::Subcommand)]
enum Command {
Create(commands::create::Opt),
VirtualPackages(commands::virtual_packages::Opt),
}

/// Entry point of the `rattler` cli.
Expand Down Expand Up @@ -70,5 +71,6 @@ async fn main() -> anyhow::Result<()> {
// Dispatch the selected comment
match opt.command {
Command::Create(opts) => commands::create::create(opts).await,
Command::VirtualPackages(opts) => commands::virtual_packages::virtual_packages(opts),
}
}
1 change: 1 addition & 0 deletions crates/rattler_virtual_packages/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ regex = { workspace = true }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
tracing = { workspace = true }
archspec = { workspace = true }

[target.'cfg(target_os="macos")'.dependencies]
plist = { workspace = true }
94 changes: 76 additions & 18 deletions crates/rattler_virtual_packages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@ pub mod libc;
pub mod linux;
pub mod osx;

use archspec::cpu::Microarchitecture;
use once_cell::sync::OnceCell;
use rattler_conda_types::{GenericVirtualPackage, PackageName, Platform, Version};
use std::hash::{Hash, Hasher};
use std::sync::Arc;

use crate::osx::ParseOsxVersionError;
use libc::DetectLibCError;
use linux::ParseLinuxVersionError;
use serde::Deserialize;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

/// An enum that represents all virtual package types provided by this library.
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
Expand Down Expand Up @@ -145,7 +148,7 @@ fn try_detect_virtual_packages() -> Result<Vec<VirtualPackage>, DetectVirtualPac
result.push(cuda.into());
}

if let Some(archspec) = Archspec::from_platform(platform) {
if let Some(archspec) = Archspec::current() {
result.push(archspec.into());
}

Expand Down Expand Up @@ -257,40 +260,95 @@ impl From<Cuda> for VirtualPackage {
}

/// Archspec describes the CPU architecture
#[derive(Clone, Eq, PartialEq, Hash, Debug, Deserialize)]
#[derive(Clone, Debug)]
pub struct Archspec {
/// A specification of the architecture family. This could be `x86_64` but it could also include
/// the full CPU family.
pub spec: String,
/// The associated microarchitecture
pub spec: Arc<Microarchitecture>,
}

impl Serialize for Archspec {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.spec.name().serialize(serializer)
}
}

impl<'de> Deserialize<'de> for Archspec {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let name = String::deserialize(deserializer)?;
let spec = archspec::cpu::Microarchitecture::known_targets()
.get(&name)
.cloned()
.unwrap_or_else(|| Arc::new(archspec::cpu::Microarchitecture::generic(&name)));
Ok(Self { spec })
}
}

impl Hash for Archspec {
fn hash<H: Hasher>(&self, state: &mut H) {
self.spec.name().hash(state);
}
}

impl PartialEq<Self> for Archspec {
fn eq(&self, other: &Self) -> bool {
self.spec.name() == other.spec.name()
}
}

impl Eq for Archspec {}

impl From<Arc<Microarchitecture>> for Archspec {
fn from(arch: Arc<Microarchitecture>) -> Self {
Self { spec: arch }
}
}

impl Archspec {
/// Returns the current CPU architecture
pub fn current() -> Option<Self> {
Self::from_platform(Platform::current())
archspec::cpu::host().ok().map(Into::into)
}

/// Returns the CPU architecture for the given platform
/// Returns the minimal supported archspec architecture for the given
/// platform.
#[allow(clippy::match_same_arms)]
pub fn from_platform(platform: Platform) -> Option<Self> {
let archspec = match platform {
// The values are taken from the archspec-json library.
// See: https://github.com/archspec/archspec-json/blob/master/cpu/microarchitectures.json
let archspec_name = match platform {
Platform::NoArch | Platform::Unknown => return None,
Platform::EmscriptenWasm32 | Platform::WasiWasm32 => "wasm32",
Platform::EmscriptenWasm32 | Platform::WasiWasm32 => return None,
Platform::Win32 | Platform::Linux32 => "x86",
Platform::Win64 | Platform::Osx64 | Platform::Linux64 => "x86_64",
Platform::LinuxAarch64 => "aarch64",
Platform::LinuxArmV6l => "armv6l",
Platform::LinuxArmV7l => "armv7l",
Platform::LinuxAarch64 | Platform::LinuxArmV6l | Platform::LinuxArmV7l => "aarch64",
Platform::LinuxPpc64le => "ppc64le",
Platform::LinuxPpc64 => "ppc64",
Platform::LinuxS390X => "s390x",
Platform::LinuxRiscv32 => "riscv32",
Platform::LinuxRiscv64 => "riscv64",
Platform::WinArm64 | Platform::OsxArm64 => "arm64",

// TODO: There must be a minimal aarch64 version that windows supports.
Platform::WinArm64 => "aarch64",

// The first every Apple Silicon Macs are based on m1.
Platform::OsxArm64 => "m1",
};

Some(Self {
spec: archspec.into(),
})
Some(
archspec::cpu::Microarchitecture::known_targets()
.get(archspec_name)
.cloned()
.unwrap_or_else(|| {
Arc::new(archspec::cpu::Microarchitecture::generic(archspec_name))
})
.into(),
)
}
}

Expand All @@ -299,7 +357,7 @@ impl From<Archspec> for GenericVirtualPackage {
GenericVirtualPackage {
name: PackageName::new_unchecked("__archspec"),
version: Version::major(1),
build_string: archspec.spec,
build_string: archspec.spec.name().to_string(),
}
}
}
Expand Down

0 comments on commit 6f95c44

Please sign in to comment.