From 89ad229a871359fce5a5fe1f0ae30a738c2853ae Mon Sep 17 00:00:00 2001 From: ijl Date: Fri, 28 Feb 2020 23:01:44 +0000 Subject: [PATCH] Support arm7l, aarch64 architectures and manylinux2014 tag The architecture, wheel names, and shared object names match what is specified in CPython and pip. arm7l and aarch64 are supported for Linux only. Target::from_target_triple() returns an Err on an unsupported OS and architecture combination. This allows building arm7l and aarch64 on manylinux1 and manylinux2010, which should not work in pip. Target::from_target_triple() could be expanded to error on this but that needs more refactoring than seems appropriate here. --- Cargo.lock | 7 -- Cargo.toml | 1 - Readme.md | 74 ++++++++++---------- src/build_options.rs | 6 +- src/target.rs | 157 +++++++++++++++++++++++++------------------ 5 files changed, 134 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 412dfa98c..d59e7d3af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -761,7 +761,6 @@ dependencies = [ "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", - "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1595,11 +1594,6 @@ dependencies = [ "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "target_info" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "tempdir" version = "0.3.7" @@ -2219,7 +2213,6 @@ dependencies = [ "checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" "checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "checksum tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "b3196bfbffbba3e57481b6ea32249fbaf590396a52505a2615adbb79d9d826d3" -"checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" diff --git a/Cargo.toml b/Cargo.toml index 260aa1c3d..aee75f901 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,6 @@ sha2 = "0.8.0" shlex = "0.1.1" structopt = "0.3.5" tar = "0.4.26" -target_info = "0.1.0" tempfile = "3.1.0" toml = "0.5.5" walkdir = "2.2.8" diff --git a/Readme.md b/Readme.md index e7a5b3e7d..1a3f5dd98 100644 --- a/Readme.md +++ b/Readme.md @@ -41,7 +41,7 @@ pyo3 will set the used python interpreter in the environment variable `PYTHON_SY Cffi wheels are compatible with all python versions, but they need to have `cffi` installed for the python used for building (`pip install cffi`). -maturin will utilize cbindgen to generate a header file. To customize the header file you can either configure cbindgen through a cbindgen.toml file inside your project root or write a setup a build script which writes a header file to `$PROJECT_ROOT/target/header.h`. +maturin will utilize cbindgen to generate a header file. To customize the header file you can either configure cbindgen through a cbindgen.toml file inside your project root or write a setup a build script which writes a header file to `$PROJECT_ROOT/target/header.h`. Based on this header file maturin generates a module which exports an `ffi` and a `lib` object. @@ -178,22 +178,22 @@ maturin can build wheels for pypy with pyo3. Note that pypy [is not compatible w ``` FLAGS: - -h, --help + -h, --help Prints help information - --no-sdist + --no-sdist Don't build a source distribution - --release + --release Pass --release to cargo - --skip-auditwheel + --skip-auditwheel [deprecated, use --manylinux instead] Don't check for manylinux compliance - --strip + --strip Strip the library for minimum file size - -V, --version + -V, --version Prints version information @@ -203,33 +203,35 @@ OPTIONS: --cargo-extra-args ... Extra arguments that will be passed to cargo as `cargo rustc [...] [arg1] [arg2] --` - + Use as `--cargo-extra-args="--my-arg"` -i, --interpreter ... The python versions to build wheels for, given as the names of the interpreters. Uses autodiscovery if not explicitly set. --manylinux Control the platform tag on linux. - + - `1`: Use the manylinux1 tag and check for compliance - `1-unchecked`: Use the manylinux1 tag without checking for compliance - `2010`: Use the manylinux2010 tag and check for compliance - - `2010-unchecked`: Use the manylinux1 tag without checking for compliance + - `2010-unchecked`: Use the manylinux2010 tag without checking for compliance + - `2014`: Use the manylinux2014 tag and check for compliance + - `2014-unchecked`: Use the manylinux2014 tag without checking for compliance - `off`: Use the native linux tag (off) - + This option is ignored on all non-linux platforms [default: 1] [possible values: 1, 1-unchecked, 2010, 2010-unchecked, off] -o, --out The directory to store the built wheels in. Defaults to a new "wheels" directory in the project's target directory - -m, --manifest-path + -m, --manifest-path The path to the Cargo.toml [default: Cargo.toml] --rustc-extra-args ... Extra arguments that will be passed to rustc as `cargo rustc [...] -- [arg1] [arg2]` - + Use as `--rustc-extra-args="--my-arg"` - --target + --target The --target option for cargo ``` @@ -237,22 +239,22 @@ OPTIONS: ``` FLAGS: - --debug + --debug Do not pass --release to cargo - -h, --help + -h, --help Prints help information - --no-sdist + --no-sdist Don't build a source distribution - --no-strip + --no-strip Strip the library for minimum file size - --skip-auditwheel + --skip-auditwheel [deprecated, use --manylinux instead] Don't check for manylinux compliance - -V, --version + -V, --version Prints version information @@ -262,29 +264,31 @@ OPTIONS: --cargo-extra-args ... Extra arguments that will be passed to cargo as `cargo rustc [...] [arg1] [arg2] --` - + Use as `--cargo-extra-args="--my-arg"` -i, --interpreter ... The python versions to build wheels for, given as the names of the interpreters. Uses autodiscovery if not explicitly set. --manylinux Control the platform tag on linux. - + - `1`: Use the manylinux1 tag and check for compliance - `1-unchecked`: Use the manylinux1 tag without checking for compliance - `2010`: Use the manylinux2010 tag and check for compliance - `2010-unchecked`: Use the manylinux1 tag without checking for compliance + - `2014`: Use the manylinux2010 tag and check for compliance + - `2014-unchecked`: Use the manylinux1 tag without checking for compliance - `off`: Use the native linux tag (off) - + This option is ignored on all non-linux platforms [default: 1] [possible values: 1, 1-unchecked, 2010, - 2010-unchecked, off] + 2010-unchecked, 2014, 2014-unchecked, off] -o, --out The directory to store the built wheels in. Defaults to a new "wheels" directory in the project's target directory -p, --password Password for pypi or your custom registry. Note that you can also pass the password through MATURIN_PASSWORD - -m, --manifest-path + -m, --manifest-path The path to the Cargo.toml [default: Cargo.toml] -r, --repository-url @@ -292,12 +296,12 @@ OPTIONS: --rustc-extra-args ... Extra arguments that will be passed to rustc as `cargo rustc [...] -- [arg1] [arg2]` - + Use as `--rustc-extra-args="--my-arg"` - --target + --target The --target option for cargo - -u, --username + -u, --username Username for pypi or your custom registry ``` @@ -305,16 +309,16 @@ OPTIONS: ``` FLAGS: - -h, --help + -h, --help Prints help information - --release + --release Pass --release to cargo - --strip + --strip Strip the library for minimum file size - -V, --version + -V, --version Prints version information @@ -324,14 +328,14 @@ OPTIONS: --cargo-extra-args ... Extra arguments that will be passed to cargo as `cargo rustc [...] [arg1] [arg2] --` - + Use as `--cargo-extra-args="--my-arg"` - -m, --manifest-path + -m, --manifest-path The path to the Cargo.toml [default: Cargo.toml] --rustc-extra-args ... Extra arguments that will be passed to rustc as `cargo rustc [...] -- [arg1] [arg2]` - + Use as `--rustc-extra-args="--my-arg"` ``` diff --git a/src/build_options.rs b/src/build_options.rs index 1955d54f7..6d07c7222 100644 --- a/src/build_options.rs +++ b/src/build_options.rs @@ -22,13 +22,15 @@ pub struct BuildOptions { /// - `1`: Use the manylinux1 tag and check for compliance{n} /// - `1-unchecked`: Use the manylinux1 tag without checking for compliance{n} /// - `2010`: Use the manylinux2010 tag and check for compliance{n} - /// - `2010-unchecked`: Use the manylinux1 tag without checking for compliance{n} + /// - `2010-unchecked`: Use the manylinux2010 tag without checking for compliance{n} + /// - `2014`: Use the manylinux2010 tag and check for compliance{n} + /// - `2014-unchecked`: Use the manylinux2014 tag without checking for compliance{n} /// - `off`: Use the native linux tag (off) /// /// This option is ignored on all non-linux platforms #[structopt( long, - possible_values = &["1", "1-unchecked", "2010", "2010-unchecked", "off"], + possible_values = &["1", "1-unchecked", "2010", "2010-unchecked", "2014", "2014-unchecked", "off"], case_insensitive = true, default_value = "1" )] diff --git a/src/target.rs b/src/target.rs index 03b00a917..379efef4d 100644 --- a/src/target.rs +++ b/src/target.rs @@ -1,13 +1,12 @@ use failure::{bail, format_err, Error}; use platform_info::*; use platforms; -use platforms::target::Arch; use serde::{Deserialize, Serialize}; use std::env; +use std::fmt; use std::path::Path; use std::path::PathBuf; use std::str::FromStr; -use target_info; /// All supported operating system #[derive(Debug, Clone, Eq, PartialEq)] @@ -29,10 +28,28 @@ pub enum Manylinux { Manylinux2010, /// Use the manylinux2010 tag but don't check for compliance Manylinux2010Unchecked, + /// Use manylinux2014 tag and check for compliance + Manylinux2014, + /// Use the manylinux2014 tag but don't check for compliance + Manylinux2014Unchecked, /// Use the native linux tag Off, } +impl fmt::Display for Manylinux { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Manylinux::Manylinux1 => write!(f, "manylinux1"), + Manylinux::Manylinux1Unchecked => write!(f, "manylinux1"), + Manylinux::Manylinux2010 => write!(f, "manylinux2010"), + Manylinux::Manylinux2010Unchecked => write!(f, "manylinux2010"), + Manylinux::Manylinux2014 => write!(f, "manylinux2014"), + Manylinux::Manylinux2014Unchecked => write!(f, "manylinux2014"), + Manylinux::Off => write!(f, "linux"), + } + } +} + impl FromStr for Manylinux { type Err = &'static str; @@ -42,39 +59,42 @@ impl FromStr for Manylinux { "1-unchecked" => Ok(Manylinux::Manylinux1Unchecked), "2010" => Ok(Manylinux::Manylinux2010), "2010-unchecked" => Ok(Manylinux::Manylinux2010Unchecked), + "2014" => Ok(Manylinux::Manylinux2014Unchecked), + "2014-unchecked" => Ok(Manylinux::Manylinux2014Unchecked), "off" => Ok(Manylinux::Off), _ => Err("Invalid value for the manylinux option"), } } } +/// All supported CPU architectures +#[derive(Debug, Clone, Eq, PartialEq)] +enum Arch { + AARCH64, + ARM7L, + X86, + X86_64, +} + +impl fmt::Display for Arch { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Arch::AARCH64 => write!(f, "aarch64"), + Arch::ARM7L => write!(f, "arm7l"), + Arch::X86 => write!(f, "i686"), + Arch::X86_64 => write!(f, "x86_64"), + } + } +} + /// The part of the current platform that is relevant when building wheels and is supported #[derive(Debug, Clone, Eq, PartialEq)] pub struct Target { os: OS, - is_64_bit: bool, + arch: Arch, } impl Target { - /// Returns the target maturin was compiled for - pub fn current() -> Self { - let os = match target_info::Target::os() { - "linux" => OS::Linux, - "windows" => OS::Windows, - "macos" => OS::Macos, - "freebsd" => OS::FreeBSD, - unsupported => panic!("The platform {} is not supported", unsupported), - }; - - let is_64_bit = match target_info::Target::pointer_width() { - "64" => true, - "32" => false, - unsupported => panic!("The pointer width {} is not supported ಠ_ಠ", unsupported), - }; - - Target { os, is_64_bit } - } - /// Uses the given target triple or tries the guess the current target by using the one used /// for compilation /// @@ -96,21 +116,42 @@ impl Target { unsupported => bail!("The operating system {:?} is not supported", unsupported), }; - let is_64_bit = match platform.target_arch { - Arch::X86_64 => true, - Arch::X86 => false, + let arch = match platform.target_arch { + platforms::target::Arch::X86_64 => Arch::X86_64, + platforms::target::Arch::X86 => Arch::X86, + platforms::target::Arch::ARM => Arch::ARM7L, + platforms::target::Arch::AARCH64 => Arch::AARCH64, unsupported => bail!("The architecture {:?} is not supported", unsupported), }; - Ok(Target { os, is_64_bit }) + // bail on any unsupported targets + match (&os, &arch) { + (OS::FreeBSD, Arch::AARCH64) => bail!("aarch64 is not supported for FreeBSD"), + (OS::FreeBSD, Arch::ARM7L) => bail!("arm7l 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() { + Ok(_) => {} + Err(error) => bail!(error), + }; + } + (OS::Macos, Arch::AARCH64) => bail!("aarch64 is not supported for macOS"), + (OS::Macos, Arch::ARM7L) => bail!("arm7l is not supported for macOS"), + (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::ARM7L) => bail!("arm7l is not supported for Windows"), + (_, _) => {} + } + Ok(Target { os, arch }) } /// Returns whether the platform is 64 bit or 32 bit pub fn pointer_width(&self) -> usize { - if self.is_64_bit { - 64 - } else { - 32 + match self.arch { + Arch::AARCH64 => 64, + Arch::ARM7L => 32, + Arch::X86 => 32, + Arch::X86_64 => 64, } } @@ -141,26 +182,8 @@ impl Target { /// Returns the platform part of the tag for the wheel name for cffi wheels pub fn get_platform_tag(&self, manylinux: &Manylinux) -> String { - match (&self.os, self.is_64_bit, manylinux) { - (&OS::Linux, true, Manylinux::Off) => "linux_x86_64".to_string(), - (&OS::Linux, false, Manylinux::Off) => "linux_i686".to_string(), - (&OS::Linux, true, Manylinux::Manylinux1) => "manylinux1_x86_64".to_string(), - (&OS::Linux, true, Manylinux::Manylinux1Unchecked) => "manylinux1_x86_64".to_string(), - (&OS::Linux, true, Manylinux::Manylinux2010) => "manylinux2010_x86_64".to_string(), - (&OS::Linux, true, Manylinux::Manylinux2010Unchecked) => { - "manylinux2010_x86_64".to_string() - } - (&OS::Linux, false, Manylinux::Manylinux1) => "manylinux1_i686".to_string(), - (&OS::Linux, false, Manylinux::Manylinux1Unchecked) => "manylinux1_i686".to_string(), - (&OS::Linux, false, Manylinux::Manylinux2010) => "manylinux2010_i686".to_string(), - (&OS::Linux, false, Manylinux::Manylinux2010Unchecked) => { - "manylinux2010_i686".to_string() - } - (&OS::Windows, true, _) => "win_amd64".to_string(), - (&OS::Windows, false, _) => "win32".to_string(), - (&OS::Macos, true, _) => "macosx_10_7_x86_64".to_string(), - (&OS::Macos, false, _) => panic!("32-bit wheels are not supported for mac os"), - (&OS::FreeBSD, true, _) => { + match (&self.os, &self.arch) { + (OS::FreeBSD, Arch::X86_64) => { let info = match PlatformInfo::new() { Ok(info) => info, Err(error) => panic!(error), @@ -168,7 +191,11 @@ impl Target { let release = info.release().replace(".", "_").replace("-", "_"); format!("freebsd_{}_amd64", release) } - (&OS::FreeBSD, false, _) => panic!("32-bit wheels are not supported for FreeBSD"), + (OS::Linux, _) => format!("{}_{}", manylinux, self.arch), + (OS::Macos, Arch::X86_64) => "macosx_10_7_x86_64".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()"), } } @@ -179,22 +206,20 @@ impl Target { /// Returns the platform for the tag in the shared libaries file name pub fn get_shared_platform_tag(&self) -> &'static str { - match self.os { - OS::Linux => { - if self.is_64_bit { - "x86_64-linux-gnu" - } else { - "i386-linux-gnu" - } + match (&self.os, &self.arch) { + (OS::FreeBSD, _) => "", // according imp.get_suffixes(), there are no such + (OS::Linux, Arch::AARCH64) => "aarch64-linux-gnueabihf", // aka armv8-linux-gnueabihf + (OS::Linux, Arch::ARM7L) => "arm-linux-gnueabihf", + (OS::Linux, Arch::X86) => "i386-linux-gnu", // not i686 + (OS::Linux, Arch::X86_64) => "x86_64-linux-gnu", + (OS::Macos, Arch::X86_64) => "darwin", + (OS::Windows, Arch::X86) => "win32", + (OS::Windows, Arch::X86_64) => "win_amd64", + (OS::Macos, _) => { + panic!("unsupported macOS Arch should not have reached get_shared_platform_tag()") } - OS::Macos => "darwin", - OS::FreeBSD => "", // according imp.get_suffixes(), there are no such - OS::Windows => { - if self.is_64_bit { - "win_amd64" - } else { - "win32" - } + (OS::Windows, _) => { + panic!("unsupported Windows Arch should not have reached get_shared_platform_tag()") } } }