servo/components/script_bindings/build.rs
delan azabani c7a215faba
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 <dazabani@igalia.com>
2025-06-06 14:54:00 +00:00

97 lines
3.2 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* 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::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
use std::time::Instant;
use std::{env, fmt};
use phf_shared::{self, FmtConst};
use serde_json::{self, Value};
fn main() {
let start = Instant::now();
let style_out_dir = PathBuf::from(env::var_os("DEP_SERVO_STYLE_CRATE_OUT_DIR").unwrap());
let css_properties_json = style_out_dir.join("css-properties.json");
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
println!("cargo:out_dir={}", out_dir.display());
println!("cargo::rerun-if-changed=webidls");
println!("cargo::rerun-if-changed=codegen");
println!("cargo::rerun-if-changed={}", css_properties_json.display());
println!("cargo::rerun-if-changed=../../third_party/WebIDL/WebIDL.py");
// NB: We aren't handling changes in `third_party/ply` here.
let status = find_python()
.arg("codegen/run.py")
.arg(&css_properties_json)
.arg(&out_dir)
.status()
.unwrap();
if !status.success() {
std::process::exit(1)
}
println!("Binding generation completed in {:?}", start.elapsed());
let json = out_dir.join("InterfaceObjectMapData.json");
let json: Value = serde_json::from_reader(File::open(json).unwrap()).unwrap();
let mut map = phf_codegen::Map::new();
for (key, value) in json.as_object().unwrap() {
let parts = value.as_array().unwrap();
map.entry(
Bytes(key),
&format!(
"Interface {{ define: {}, enabled: {} }}",
parts[0].as_str().unwrap(),
parts[1].as_str().unwrap()
),
);
}
let phf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("InterfaceObjectMapPhf.rs");
let mut phf = File::create(phf).unwrap();
writeln!(
&mut phf,
"pub(crate) static MAP: phf::Map<&'static [u8], Interface> = {};",
map.build(),
)
.unwrap();
}
#[derive(Eq, Hash, PartialEq)]
struct Bytes<'a>(&'a str);
impl FmtConst for Bytes<'_> {
fn fmt_const(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "b\"{}\"", self.0)
}
}
impl phf_shared::PhfHash for Bytes<'_> {
fn phf_hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
self.0.as_bytes().phf_hash(hasher)
}
}
/// 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).
///
/// More details: <https://book.servo.org/hacking/setting-up-your-environment.html#check-tools>
///
/// 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"]);
if command.output().is_ok_and(|out| out.status.success()) {
return command;
}
panic!("Can't find python (tried `{command:?}`)! Is uv installed and in PATH?")
}