From c7a215faba8ed2ebfa1624b020d82303130f0c9e Mon Sep 17 00:00:00 2001 From: delan azabani Date: Fri, 6 Jun 2025 16:54:00 +0200 Subject: [PATCH] Fix `cargo build -p libservo` on macOS 13 by running Python via `uv` (#37290) The correct way to run Python when building Servo is `uv run python`, unless we are running as a descendant of `uv run python`. In that case, we can use either `uv run python` or `python` (uv does not provide a `python3` on Windows \*). \* for the astute reader, yes, this causes problems for mozjs, which only tries `python3` unless PYTHON3=python :))) Testing: tested manually on macOS 13 (see below), and will be tested in CI Fixes: #37289 ![Screenshot_servo-macos13_2025-06-06_11:35:52](https://github.com/user-attachments/assets/01d4ea38-d405-452f-aeb9-75aada13c907) Signed-off-by: Delan Azabani --- components/script_bindings/build.rs | 59 ++++++----------------------- components/servo/build.rs | 53 +++++++------------------- 2 files changed, 25 insertions(+), 87 deletions(-) diff --git a/components/script_bindings/build.rs b/components/script_bindings/build.rs index b11e3d1cfdf..d2ff8ceb4a1 100644 --- a/components/script_bindings/build.rs +++ b/components/script_bindings/build.rs @@ -27,7 +27,7 @@ fn main() { println!("cargo::rerun-if-changed=../../third_party/WebIDL/WebIDL.py"); // NB: We aren't handling changes in `third_party/ply` here. - let status = Command::new(find_python()) + let status = find_python() .arg("codegen/run.py") .arg(&css_properties_json) .arg(&out_dir) @@ -78,55 +78,20 @@ impl phf_shared::PhfHash for Bytes<'_> { } } -/// Tries to find a suitable python +/// Tries to find a suitable python, which in Servo is always `uv run python` unless we are running +/// as a descendant of `uv run python`. In that case, we can use either `uv run python` or `python` +/// (uv does not provide a `python3` on Windows). /// -/// Algorithm -/// 1. Trying to find python3/python in $VIRTUAL_ENV (this should be from Servo's venv) -/// 2. Checking PYTHON3 (set by mach) -/// 3. Falling back to the system installation. +/// More details: /// -/// Note: This function should be kept in sync with the version in `components/servo/build.rs` -fn find_python() -> PathBuf { - let mut candidates = vec![]; - if let Some(venv) = env::var_os("VIRTUAL_ENV") { - let bin_directory = PathBuf::from(venv).join("bin"); +/// Note: This function should be kept in sync with the version in `components/script/build.rs` +fn find_python() -> Command { + let mut command = Command::new("uv"); + command.args(["run", "python"]); - let python3 = bin_directory.join("python3"); - if python3.exists() { - candidates.push(python3); - } - let python = bin_directory.join("python"); - if python.exists() { - candidates.push(python); - } - }; - if let Some(python3) = env::var_os("PYTHON3") { - let python3 = PathBuf::from(python3); - if python3.exists() { - candidates.push(python3); - } + if command.output().is_ok_and(|out| out.status.success()) { + return command; } - let system_python = ["python3", "python"].map(PathBuf::from); - candidates.extend_from_slice(&system_python); - - for name in &candidates { - // Command::new() allows us to omit the `.exe` suffix on windows - if Command::new(name) - .arg("--version") - .output() - .is_ok_and(|out| out.status.success()) - { - return name.to_owned(); - } - } - let candidates = candidates - .into_iter() - .map(|c| c.into_os_string()) - .collect::>(); - panic!( - "Can't find python (tried {:?})! Try enabling Servo's Python venv, \ - setting the PYTHON3 env var or adding python3 to PATH.", - candidates.join(", ".as_ref()) - ) + panic!("Can't find python (tried `{command:?}`)! Is uv installed and in PATH?") } diff --git a/components/servo/build.rs b/components/servo/build.rs index 0b6b087547b..d610d1cfe36 100644 --- a/components/servo/build.rs +++ b/components/servo/build.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use std::path::{Path, PathBuf}; +use std::path::Path; use std::process::Command; use std::{env, fs}; @@ -10,7 +10,7 @@ fn main() { if cfg!(feature = "media-gstreamer") { println!("cargo:rerun-if-changed=../../python/servo/gstreamer.py"); - let output = Command::new(find_python()) + let output = find_python() .arg("../../python/servo/gstreamer.py") .arg(std::env::var_os("TARGET").unwrap()) .output() @@ -25,47 +25,20 @@ fn main() { } } -/// Tries to find a suitable python +/// Tries to find a suitable python, which in Servo is always `uv run python` unless we are running +/// as a descendant of `uv run python`. In that case, we can use either `uv run python` or `python` +/// (uv does not provide a `python3` on Windows). /// -/// Algorithm -/// 1. Trying to find python3/python in $VIRTUAL_ENV (this should be from servos venv) -/// 2. Checking PYTHON3 (set by mach) -/// 3. Falling back to the system installation. +/// More details: /// /// Note: This function should be kept in sync with the version in `components/script/build.rs` -fn find_python() -> PathBuf { - let mut candidates = vec![]; - if let Some(venv) = env::var_os("VIRTUAL_ENV") { - // See: https://docs.python.org/3/library/venv.html#how-venvs-work - let bin_dir = if cfg!(windows) { "Scripts" } else { "bin" }; - let bin_directory = PathBuf::from(venv).join(bin_dir); - candidates.push(bin_directory.join("python3")); - candidates.push(bin_directory.join("python")); - } - if let Some(python3) = env::var_os("PYTHON3") { - candidates.push(PathBuf::from(python3)); +fn find_python() -> Command { + let mut command = Command::new("uv"); + command.args(["run", "python"]); + + if command.output().is_ok_and(|out| out.status.success()) { + return command; } - let system_python = ["python3", "python"].map(PathBuf::from); - candidates.extend_from_slice(&system_python); - - for name in &candidates { - // Command::new() allows us to omit the `.exe` suffix on windows - if Command::new(name) - .arg("--version") - .output() - .is_ok_and(|out| out.status.success()) - { - return name.to_owned(); - } - } - let candidates = candidates - .into_iter() - .map(|c| c.into_os_string()) - .collect::>(); - panic!( - "Can't find python (tried {:?})! Try enabling Servo's Python venv, \ - setting the PYTHON3 env var or adding python3 to PATH.", - candidates.join(", ".as_ref()) - ) + panic!("Can't find python (tried `{command:?}`)! Is uv installed and in PATH?") }