Add support for delocating macOS wheels#17336
Conversation
afab653 to
f593a05
Compare
f593a05 to
f0e8c89
Compare
f0e8c89 to
55e7d53
Compare
55e7d53 to
2fcfd67
Compare
2fcfd67 to
5250e52
Compare
5250e52 to
915cb56
Compare
49bf890 to
fb8f82c
Compare
fb8f82c to
c7dddf2
Compare
b3467e9 to
2ca2ec0
Compare
2ca2ec0 to
16795a9
Compare
f545efc to
15c0925
Compare
crates/uv-static/src/env_vars.rs
Outdated
| /// Search path for dynamic libraries on macOS (checked before system paths). | ||
| /// | ||
| /// Used during wheel delocating to find library dependencies. | ||
| #[attr_added_in("0.9.22")] |
There was a problem hiding this comment.
| #[attr_added_in("0.9.22")] | |
| #[attr_added_in("next version")] |
15c0925 to
6781fa4
Compare
cacc338 to
d04253c
Compare
d04253c to
76adaf0
Compare
| // @loader_path and @executable_path are relative to the binary containing the reference. | ||
| let parent = binary_path.parent()?; | ||
| let resolved = parent.join(relative); | ||
| if let Ok(path) = resolved.canonicalize() { |
There was a problem hiding this comment.
What happens at runtime with a library like this, would this create a wheel with a shared library that fails to load?
|
|
||
| // Check macOS version compatibility against target version. | ||
| if let Some(version) = target_version { | ||
| check_macos_version_compatible(lib_path, version)?; |
There was a problem hiding this comment.
This and the find_max_macos_version below look off: In the Python delocate: there's a function that runs over the wheel directory after the libs have been copied and computes the minimum of all libs in the new wheel, I think that's libraries + binaries in our terminology (https://github.com/matthew-brett/delocate/blob/a97bc907ea5fab9256e2c92b995b332605fcd98b/delocate/delocating.py#L660-L691). It has the option to check for the required macos version support, but that check only runs if MACOSX_DEPLOYMENT_TARGET is set, otherwise it uses the minimum macos version possible with all binaries/libraries in the wheel. Do we have a test input wheel to check this?
| new_name | ||
| ); | ||
|
|
||
| let output = Command::new("install_name_tool") |
There was a problem hiding this comment.
More something for a follow-up PR, but where did we end up on using arwen to avoid the problems with subprocess calls? It's not tested enough rn, but were there any architectural concerns? mid-term, I rather fix bugs in a rust library than working around install_name_tool.
There was a problem hiding this comment.
CC @geofft who has a way doing it without full arwen, avoiding rewriting the binary for just patching the relevant sections.
| PathNotInWheel { path: PathBuf, wheel_dir: PathBuf }, | ||
|
|
||
| #[error("Unsupported Mach-O format: {0}")] | ||
| UnsupportedFormat(String), |
| MachOParse(String), | ||
|
|
||
| #[error("Dependency not found: {name} (required by {})", required_by.user_display())] | ||
| DependencyNotFound { name: String, required_by: PathBuf }, |
| pub use delocate::{DelocateOptions, delocate_wheel, list_wheel_dependencies}; | ||
| pub use error::DelocateError; | ||
| pub use macho::{Arch, MachOFile}; | ||
| pub use uv_platform::MacOSVersion; |
There was a problem hiding this comment.
Why is this external symbol pub-use?
| } | ||
|
|
||
| #[test] | ||
| fn test_macos_version_ordering() { |
There was a problem hiding this comment.
I'm not sure if we need that test, it tests a #[derive(Ord)] in combination with the field order.
| } | ||
|
|
||
| #[test] | ||
| fn test_find_dist_info() { |
There was a problem hiding this comment.
This now covered by the existing test suite
Summary
This PR adds support for delocating macOS wheels. The behavior is not yet exposed on the CLI; it's only intended for internal-to-uv use. The implementation is based on https://github.com/matthew-brett/delocate, specifically
delocate-listdeps {wheel}to list library dependencies (exposed aslist_wheel_dependencies()) anddelocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}to copy external libraries into binaries (exposed asdelocate_wheel()).