From d995b50d218ed7606cc16e088b0a21d752233049 Mon Sep 17 00:00:00 2001 From: messense Date: Mon, 28 Nov 2022 20:46:20 +0800 Subject: [PATCH] Feature gate zig and xwin based cross compiling * `cargo build`: 34.26s * `cargo build --no-default-features`: 26.25s --- .github/workflows/test.yml | 1 + Cargo.toml | 10 ++++-- src/build_context.rs | 1 + src/build_options.rs | 8 ++++- src/compile.rs | 65 ++++++++++++++++++++++++++------------ src/develop.rs | 1 + src/main.rs | 28 +++++++++------- src/target.rs | 6 ++-- 8 files changed, 81 insertions(+), 39 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ca0be16b5..a8f0678e5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -462,6 +462,7 @@ jobs: # Caching - name: Cache cargo build uses: Swatinem/rust-cache@v2 + - run: cargo build --no-default-features - name: cargo build run: cargo build --all diff --git a/Cargo.toml b/Cargo.toml index 455cf1d83..5f7beb265 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,8 +25,8 @@ base64 = "0.13.0" glob = "0.3.0" cargo_metadata = "0.15.2" cargo-options = "0.5.2" -cargo-zigbuild = "0.14.1" -cargo-xwin = { version = "0.13.0", default-features = false } +cargo-zigbuild = { version = "0.14.1", optional = true } +cargo-xwin = { version = "0.13.0", default-features = false, optional = true } cbindgen = { version = "0.24.2", default-features = false } uniffi_bindgen = "0.21.0" flate2 = "1.0.18" @@ -88,12 +88,16 @@ rustversion = "1.0.9" trycmd = "0.14.0" [features] -default = ["log", "upload", "rustls"] +default = ["cross-compile", "log", "upload", "rustls"] upload = ["ureq", "multipart", "rpassword", "configparser", "bytesize"] password-storage = ["upload", "keyring"] log = ["tracing-subscriber"] rustls = ["ureq/tls", "cargo-xwin/rustls-tls"] native-tls = ["ureq/native-tls", "native-tls-crate", "cargo-xwin/native-tls"] +# cross compile using zig or xwin +cross-compile = ["zig", "xwin"] +zig = ["cargo-zigbuild"] +xwin = ["cargo-xwin"] # Internal feature to speed up the tests significantly faster-tests = [] # Deprecated features, keep it now for compatibility diff --git a/src/build_context.rs b/src/build_context.rs index 86af7d5fb..0b0ba6ae7 100644 --- a/src/build_context.rs +++ b/src/build_context.rs @@ -171,6 +171,7 @@ pub struct BuildContext { /// Skip checking the linked libraries for manylinux/musllinux compliance pub skip_auditwheel: bool, /// When compiling for manylinux, use zig as linker to ensure glibc version compliance + #[cfg(feature = "zig")] pub zig: bool, /// Whether to use the the manylinux/musllinux or use the native linux tag (off) pub platform_tag: Vec, diff --git a/src/build_options.rs b/src/build_options.rs index 1faccafa3..eb47106b0 100644 --- a/src/build_options.rs +++ b/src/build_options.rs @@ -179,6 +179,7 @@ pub struct BuildOptions { /// Default to manylinux2014/manylinux_2_17 if you do not specify an `--compatibility` /// /// Make sure you installed zig with `pip install maturin[zig]` + #[cfg(feature = "zig")] #[arg(long)] pub zig: bool, @@ -598,6 +599,10 @@ impl BuildOptions { let skip_auditwheel = pyproject.map(|x| x.skip_auditwheel()).unwrap_or_default() || self.skip_auditwheel; let platform_tags = if self.platform_tag.is_empty() { + #[cfg(feature = "zig")] + let use_zig = self.zig; + #[cfg(not(feature = "zig"))] + let use_zig = false; let compatibility = pyproject .and_then(|x| { if x.compatibility().is_some() { @@ -605,7 +610,7 @@ impl BuildOptions { } x.compatibility() }) - .or(if self.zig { + .or(if use_zig { if target.is_musl_target() { // Zig bundles musl 1.2 Some(PlatformTag::Musllinux { x: 1, y: 2 }) @@ -714,6 +719,7 @@ impl BuildOptions { release, strip, skip_auditwheel, + #[cfg(feature = "zig")] zig: self.zig, platform_tag: platform_tags, interpreter, diff --git a/src/compile.rs b/src/compile.rs index 79a71e804..0a0b23704 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1,6 +1,8 @@ use crate::build_context::BridgeModel; use crate::target::RUST_1_64_0; -use crate::{BuildContext, PlatformTag, PythonInterpreter, Target}; +#[cfg(feature = "zig")] +use crate::PlatformTag; +use crate::{BuildContext, PythonInterpreter, Target}; use anyhow::{anyhow, bail, Context, Result}; use fat_macho::FatWriter; use fs_err::{self as fs, File}; @@ -305,34 +307,55 @@ fn compile_target( let target_triple = target.target_triple(); let mut build_command = if target.is_msvc() && target.cross_compiling() { - let mut build = cargo_xwin::Rustc::from(cargo_rustc); + #[cfg(feature = "xwin")] + { + let mut build = cargo_xwin::Rustc::from(cargo_rustc); - build.target = vec![target_triple.to_string()]; - build.build_command()? - } else { - let mut build = cargo_zigbuild::Rustc::from(cargo_rustc); - if !context.zig { - build.disable_zig_linker = true; + build.target = vec![target_triple.to_string()]; + build.build_command()? + } + #[cfg(not(feature = "xwin"))] + { if target.user_specified { - build.target = vec![target_triple.to_string()]; + cargo_rustc.target = vec![target_triple.to_string()]; } - } else { - build.enable_zig_ar = true; - let zig_triple = if target.is_linux() && !target.is_musl_target() { - match context.platform_tag.iter().find(|tag| tag.is_manylinux()) { - Some(PlatformTag::Manylinux { x, y }) => { - format!("{}.{}.{}", target_triple, x, y) - } - _ => target_triple.to_string(), + cargo_rustc.command() + } + } else { + #[cfg(feature = "zig")] + { + let mut build = cargo_zigbuild::Rustc::from(cargo_rustc); + if !context.zig { + build.disable_zig_linker = true; + if target.user_specified { + build.target = vec![target_triple.to_string()]; } } else { - target_triple.to_string() - }; - build.target = vec![zig_triple]; + build.enable_zig_ar = true; + let zig_triple = if target.is_linux() && !target.is_musl_target() { + match context.platform_tag.iter().find(|tag| tag.is_manylinux()) { + Some(PlatformTag::Manylinux { x, y }) => { + format!("{}.{}.{}", target_triple, x, y) + } + _ => target_triple.to_string(), + } + } else { + target_triple.to_string() + }; + build.target = vec![zig_triple]; + } + build.build_command()? + } + #[cfg(not(feature = "zig"))] + { + if target.user_specified { + cargo_rustc.target = vec![target_triple.to_string()]; + } + cargo_rustc.command() } - build.build_command()? }; + #[cfg(feature = "zig")] if context.zig { // Pass zig command to downstream, eg. python3-dll-a if let Ok((zig_cmd, zig_args)) = cargo_zigbuild::Zig::find_zig() { diff --git a/src/develop.rs b/src/develop.rs index 99e17ba49..98514792a 100644 --- a/src/develop.rs +++ b/src/develop.rs @@ -57,6 +57,7 @@ pub fn develop( bindings, out: Some(wheel_dir.path().to_path_buf()), skip_auditwheel: false, + #[cfg(feature = "zig")] zig: false, universal2: false, cargo: CargoOptions { diff --git a/src/main.rs b/src/main.rs index 1e7f64d37..b059a255e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ //! Run with --help for usage information use anyhow::{bail, Context, Result}; +#[cfg(feature = "zig")] use cargo_zigbuild::Zig; use clap::{CommandFactory, Parser, Subcommand}; use maturin::{ @@ -153,6 +154,7 @@ enum Opt { shell: clap_complete_command::Shell, }, /// Zig linker wrapper + #[cfg(feature = "zig")] #[command(subcommand, hide = true)] Zig(Zig), } @@ -278,17 +280,20 @@ fn run() -> Result<()> { #[cfg(feature = "log")] tracing_subscriber::fmt::init(); - // Allow symlink `maturin` to `ar` to invoke `zig ar` - // See https://github.com/messense/cargo-zigbuild/issues/52 - let mut args = env::args(); - let program_path = PathBuf::from(args.next().expect("no program path")); - let program_name = program_path.file_stem().expect("no program name"); - if program_name.eq_ignore_ascii_case("ar") { - let zig = Zig::Ar { - args: args.collect(), - }; - zig.execute()?; - return Ok(()); + #[cfg(feature = "zig")] + { + // Allow symlink `maturin` to `ar` to invoke `zig ar` + // See https://github.com/messense/cargo-zigbuild/issues/52 + let mut args = env::args(); + let program_path = PathBuf::from(args.next().expect("no program path")); + let program_name = program_path.file_stem().expect("no program name"); + if program_name.eq_ignore_ascii_case("ar") { + let zig = Zig::Ar { + args: args.collect(), + }; + zig.execute()?; + return Ok(()); + } } let opt = Opt::parse(); @@ -402,6 +407,7 @@ fn run() -> Result<()> { Opt::Completions { shell } => { shell.generate(&mut Opt::command(), &mut io::stdout()); } + #[cfg(feature = "zig")] Opt::Zig(subcommand) => { subcommand .execute() diff --git a/src/target.rs b/src/target.rs index 5263f8538..b2d351ceb 100644 --- a/src/target.rs +++ b/src/target.rs @@ -779,9 +779,9 @@ pub(crate) fn rustc_macosx_target_version(target: &str) -> (u16, u16) { .context("rustc output does not contain llvm-target")? .as_str() .context("llvm-target is not a string")?; - let triple: Triple = llvm_target.parse()?; - let (major, minor) = match triple.operating_system { - OperatingSystem::MacOSX { major, minor, .. } => (major, minor), + let triple = llvm_target.parse::(); + let (major, minor) = match triple.map(|t| t.operating_system) { + Ok(OperatingSystem::MacOSX { major, minor, .. }) => (major, minor), _ => fallback_version, }; Ok((major, minor))