uv_python/
macos_dylib.rs

1use std::{io::ErrorKind, path::PathBuf};
2
3use uv_fs::Simplified as _;
4use uv_warnings::warn_user;
5
6use crate::managed::ManagedPythonInstallation;
7
8pub fn patch_dylib_install_name(dylib: PathBuf) -> Result<(), Error> {
9    let output = match std::process::Command::new("install_name_tool")
10        .arg("-id")
11        .arg(&dylib)
12        .arg(&dylib)
13        .output()
14    {
15        Ok(output) => output,
16        Err(e) => {
17            let e = if e.kind() == ErrorKind::NotFound {
18                Error::MissingInstallNameTool
19            } else {
20                e.into()
21            };
22            return Err(e);
23        }
24    };
25
26    if !output.status.success() {
27        let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
28        return Err(Error::RenameError { dylib, stderr });
29    }
30
31    Ok(())
32}
33
34#[derive(thiserror::Error, Debug)]
35pub enum Error {
36    #[error(transparent)]
37    Io(#[from] std::io::Error),
38    #[error("`install_name_tool` is not available on this system.
39This utility is part of macOS Developer Tools. Please ensure that the Xcode Command Line Tools are installed by running:
40
41    xcode-select --install
42
43For more information, see: https://developer.apple.com/xcode/")]
44    MissingInstallNameTool,
45    #[error("Failed to update the install name of the Python dynamic library located at `{}`", dylib.user_display())]
46    RenameError { dylib: PathBuf, stderr: String },
47}
48
49impl Error {
50    /// Emit a user-friendly warning about the patching failure.
51    pub fn warn_user(&self, installation: &ManagedPythonInstallation) {
52        let error = if tracing::enabled!(tracing::Level::DEBUG) {
53            format!("\nUnderlying error: {self}")
54        } else {
55            String::new()
56        };
57        warn_user!(
58            "Failed to patch the install name of the dynamic library for {}. This may cause issues when building Python native extensions.{}",
59            installation.executable(false).simplified_display(),
60            error
61        );
62    }
63}