uutils / platform-info

A cross-platform way to get information about your machine
MIT License
85 stars 25 forks source link

machine returns x86_64 on Apple M2 (arm64) #25

Closed AdamIsrael closed 2 years ago

AdamIsrael commented 2 years ago

Observed behavior: machine returns x86_64. Expected behavior: machine returns arm64.

I recently switched from testing on an Intel Macbook Pro to an M2 chip, which is arm64. I noticed that platform-info is returning x86_64, though, when I'd expect it to return arm64. Am I just thinking about it wrong?

sylvestre commented 2 years ago

no, you are probably correct :) would you like to try to fix it? should be easy

AdamIsrael commented 2 years ago

Yep, I'll take that challenge. :grinning: It might actually be a problem with the libc crate, but I'll write a test to confirm and then see about patching it.

AdamIsrael commented 2 years ago

TIL a bunch about Apple Silicon, M2, and universal binaries.

tl;dr: machine is technically correct in returning x86_64 because by default Rust is building ax86_64 binary, which is run through Rosetta on Apple Silicon. As such, I'll close this issue but leave some commentary that may be useful if anyone else stumbles across this.

To test this, I created a simple Rust application, using libc the same way platform-info does:

extern crate libc;
use self::libc::{uname, utsname};

use std::ffi::CStr;
use std::mem::MaybeUninit;

macro_rules! cstr2cow {
    ($v:expr) => {
        CStr::from_ptr($v.as_ref().as_ptr()).to_string_lossy()
    };
}

fn main() {
    unsafe {
        let mut uts = MaybeUninit::<utsname>::uninit();
        if uname(uts.as_mut_ptr()) != -1 {
            let uts = uts.assume_init();
            println!("{}", cstr2cow!(uts.machine));
        }
    }
}

It is possible to build a native arm64 binary:

rustup target add aarch64-apple-darwin
cargo build --target aarch64-apple-darwin

With this binary, machine returns arm64. There's still an open issue about linking a universal binary via cargo but in the meantime it can be done manually via and additional step:

lipo -create -output arch target/release/arch target/aarch64-apple-darwin/release/arch

This creates a Universal Binary containing both architectures:

$ file arch
arch: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64Mach-O 64-bit executable arm64]
arch (for architecture x86_64): Mach-O 64-bit executable x86_64
arch (for architecture arm64):  Mach-O 64-bit executable arm64

Running the Universal Binary results in this, which I presume is the default architecture

$ arch
arm64