From 93eca2846c8a9335b3bb0e17785f6ded67200367 Mon Sep 17 00:00:00 2001 From: messense Date: Sat, 16 Jan 2021 13:39:48 +0800 Subject: [PATCH] Add support for macOS universal2 wheel --- src/compile.rs | 74 +++++++++++++++++++++++++++++++++++++++++++++++++- src/target.rs | 25 +++++++++++++++-- 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/compile.rs b/src/compile.rs index 1c02004d8..89d5aee83 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1,7 +1,7 @@ use crate::build_context::BridgeModel; use crate::BuildContext; use crate::PythonInterpreter; -use anyhow::{bail, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use fs_err::File; use std::collections::HashMap; use std::io::{BufReader, Read}; @@ -16,6 +16,74 @@ pub fn compile( context: &BuildContext, python_interpreter: Option<&PythonInterpreter>, bindings_crate: &BridgeModel, +) -> Result> { + if context.target.is_macos_universal2() { + let arm64_artifact = compile_target( + context, + python_interpreter, + bindings_crate, + Some("aarch64-apple-darwin"), + ) + .context("Failed to build a arm64 library through cargo")? + .get("cdylib") + .cloned() + .ok_or_else(|| { + anyhow!( + "Cargo didn't build a cdylib. Did you miss crate-type = [\"cdylib\"] \ + in the lib section of your Cargo.toml?", + ) + })?; + let x86_64_artifact = compile_target( + context, + python_interpreter, + bindings_crate, + Some("x86_64-apple-darwin"), + ) + .context("Failed to build a x86_64 library through cargo")? + .get("cdylib") + .cloned() + .ok_or_else(|| { + anyhow!( + "Cargo didn't build a cdylib. Did you miss crate-type = [\"cdylib\"] \ + in the lib section of your Cargo.toml?", + ) + })?; + // Use lipo to create an universal dylib + let cdylib_path = arm64_artifact + .display() + .to_string() + .replace("aarch64-apple-darwin/", ""); + let mut cmd = Command::new("lipo"); + cmd.arg("-create") + .arg("-output") + .arg(&cdylib_path) + .arg(arm64_artifact) + .arg(x86_64_artifact); + let lipo = cmd.spawn().context("Failed to run lipo")?; + let output = lipo + .wait_with_output() + .expect("Failed to wait on lipo child process"); + + if !output.status.success() { + bail!( + r#"lipo finished with "{}": {}"#, + output.status, + String::from_utf8_lossy(&output.stderr) + ) + } + let mut result = HashMap::new(); + result.insert("cdylib".to_string(), PathBuf::from(cdylib_path)); + Ok(result) + } else { + compile_target(context, python_interpreter, bindings_crate, None) + } +} + +fn compile_target( + context: &BuildContext, + python_interpreter: Option<&PythonInterpreter>, + bindings_crate: &BridgeModel, + target: Option<&str>, ) -> Result> { let mut shared_args = vec!["--manifest-path", context.manifest_path.to_str().unwrap()]; @@ -33,6 +101,10 @@ pub fn compile( if context.release { shared_args.push("--release"); } + if let Some(target) = target { + shared_args.push("--target"); + shared_args.push(target); + } let cargo_args = vec!["rustc", "--message-format", "json"]; diff --git a/src/target.rs b/src/target.rs index d13cc342b..4e8cf7d63 100644 --- a/src/target.rs +++ b/src/target.rs @@ -58,6 +58,7 @@ enum Arch { ARMV7L, POWERPC64LE, POWERPC64, + Universal2, X86, X86_64, } @@ -69,6 +70,7 @@ impl fmt::Display for Arch { Arch::ARMV7L => write!(f, "armv7l"), Arch::POWERPC64LE => write!(f, "ppc64le"), Arch::POWERPC64 => write!(f, "ppc64"), + Arch::Universal2 => write!(f, "universal2"), Arch::X86 => write!(f, "i686"), Arch::X86_64 => write!(f, "x86_64"), } @@ -108,7 +110,13 @@ impl Target { platforms::target::Arch::X86_64 => Arch::X86_64, platforms::target::Arch::X86 => Arch::X86, platforms::target::Arch::ARM => Arch::ARMV7L, - platforms::target::Arch::AARCH64 => Arch::AARCH64, + platforms::target::Arch::AARCH64 => { + if os == OS::Macos { + Arch::Universal2 // macOS with Apple Silicon + } else { + Arch::AARCH64 + } + } platforms::target::Arch::POWERPC64 if platform.target_triple.starts_with("powerpc64-") => { @@ -126,6 +134,7 @@ impl Target { match (&os, &arch) { (OS::FreeBSD, Arch::AARCH64) => bail!("aarch64 is not supported for FreeBSD"), (OS::FreeBSD, Arch::ARMV7L) => bail!("armv7l is not supported for FreeBSD"), + (OS::FreeBSD, Arch::Universal2) => bail!("universal2 is not supported for FreeBSD"), (OS::FreeBSD, Arch::X86) => bail!("32-bit wheels are not supported for FreeBSD"), (OS::FreeBSD, Arch::X86_64) => { match PlatformInfo::new() { @@ -137,6 +146,7 @@ impl Target { (OS::Macos, Arch::X86) => bail!("32-bit wheels are not supported for macOS"), (OS::Windows, Arch::AARCH64) => bail!("aarch64 is not supported for Windows"), (OS::Windows, Arch::ARMV7L) => bail!("armv7l is not supported for Windows"), + (OS::Windows, Arch::Universal2) => bail!("universal2 is not supported for Windows"), (_, _) => {} } Ok(Target { os, arch }) @@ -149,6 +159,7 @@ impl Target { Arch::ARMV7L => 32, Arch::POWERPC64 => 64, Arch::POWERPC64LE => 64, + Arch::Universal2 => 64, Arch::X86 => 32, Arch::X86_64 => 64, } @@ -174,6 +185,11 @@ impl Target { self.os == OS::Macos } + /// Returns true if the current platform is mac os and arch is universal2 + pub fn is_macos_universal2(&self) -> bool { + self.os == OS::Macos && self.arch == Arch::Universal2 + } + /// Returns true if the current platform is windows pub fn is_windows(&self) -> bool { self.os == OS::Windows @@ -193,6 +209,7 @@ impl Target { (OS::Linux, _) => format!("{}_{}", manylinux, self.arch), (OS::Macos, Arch::X86_64) => "macosx_10_7_x86_64".to_string(), (OS::Macos, Arch::AARCH64) => "macosx_11_0_arm64".to_string(), + (OS::Macos, Arch::Universal2) => "macosx_10_9_universal2".to_string(), (OS::Windows, Arch::X86) => "win32".to_string(), (OS::Windows, Arch::X86_64) => "win_amd64".to_string(), (_, _) => panic!("unsupported target should not have reached get_platform_tag()"), @@ -204,7 +221,7 @@ impl Target { vec![format!("py3-none-{}", self.get_platform_tag(&manylinux))] } - /// Returns the platform for the tag in the shared libaries file name + /// Returns the platform for the tag in the shared libraries file name pub fn get_shared_platform_tag(&self) -> &'static str { match (&self.os, &self.arch) { (OS::FreeBSD, _) => "", // according imp.get_suffixes(), there are no such @@ -216,8 +233,12 @@ impl Target { (OS::Linux, Arch::X86_64) => "x86_64-linux-gnu", (OS::Macos, Arch::X86_64) => "darwin", (OS::Macos, Arch::AARCH64) => "darwin", + (OS::Macos, Arch::Universal2) => "darwin", (OS::Windows, Arch::X86) => "win32", (OS::Windows, Arch::X86_64) => "win_amd64", + (OS::Linux, _) => { + panic!("unsupported Linux Arch should not have reached get_shared_platform_tag()") + } (OS::Macos, _) => { panic!("unsupported macOS Arch should not have reached get_shared_platform_tag()") }