diff --git a/build.rs b/build.rs index 493c8b0b74f..29610e593b8 100644 --- a/build.rs +++ b/build.rs @@ -33,6 +33,7 @@ struct InterpreterConfig { base_prefix: String, executable: String, machine: String, + maxsize_bits: Option, } #[derive(Deserialize, Debug, Clone, PartialEq)] @@ -181,6 +182,7 @@ fn load_cross_compile_info() -> Result<(InterpreterConfig, HashMap Result { } } - check_target_architecture(&interpreter_config.machine)?; + check_target_architecture(interpreter_config)?; let is_extension_module = env::var_os("CARGO_FEATURE_EXTENSION_MODULE").is_some(); if !is_extension_module || cfg!(target_os = "windows") { @@ -517,32 +520,39 @@ fn configure(interpreter_config: &InterpreterConfig) -> Result { Ok(flags) } -fn check_target_architecture(python_machine: &str) -> Result<()> { +fn check_target_architecture(interpreter_config: &InterpreterConfig) -> Result<()> { // Try to check whether the target architecture matches the python library - let target_arch = match env::var("CARGO_CFG_TARGET_ARCH") - .as_ref() - .map(|e| e.as_str()) - { - Ok("x86_64") => Some("64-bit"), - Ok("x86") => Some("32-bit"), - _ => None, // It might be possible to recognise other architectures, this will do for now. + let rust_target = match env::var("CARGO_CFG_TARGET_POINTER_WIDTH")?.as_str() { + "64" => "64-bit", + "32" => "32-bit", + x => bail!("unexpected Rust target pointer width: {}", x), }; - let python_arch = match python_machine { - "AMD64" | "x86_64" => Some("64-bit"), - "i686" | "x86" => Some("32-bit"), - _ => None, // It might be possible to recognise other architectures, this will do for now. + // Why are we using at sys.maxsize here, rather than just + // platform.architecture()? Because the latter can give weird results on + // macOS. See https://stackoverflow.com/a/1405971/823869. + let python_target = match interpreter_config.maxsize_bits { + // sys.maxsize is a signed value, so it's one bit shorter than the + // pointer width. + Some(63) => "64-bit", + Some(31) => "32-bit", + None => { + // Unset, e.g. because we're cross-compiling. Don't check anything + // in this case. + return Ok(()); + } + Some(n) => bail!("unexpected Python maxsize_bits: {}", n), }; - match (target_arch, python_arch) { - // If we could recognise both, and they're different, fail. - (Some(t), Some(p)) if p != t => bail!( + if rust_target != python_target { + bail!( "Your Rust target architecture ({}) does not match your python interpreter ({})", - t, - p - ), - _ => Ok(()), + rust_target, + python_target + ); } + + Ok(()) } fn check_rustc_version() -> Result<()> {