From f92447772eb8a8de184f1d8b76b6f77d6646ee9e Mon Sep 17 00:00:00 2001 From: konsti Date: Tue, 28 May 2024 18:07:39 +0200 Subject: [PATCH] Support x86 windows (#3873) Add trampolines for x86 windows. Closes https://github.com/astral-sh/uv/issues/3660. --- .github/workflows/ci.yml | 2 +- crates/install-wheel-rs/src/lib.rs | 4 +++- crates/install-wheel-rs/src/wheel.rs | 16 ++++++++++++++++ crates/uv-trampoline/README.md | 15 +++++++++++---- crates/uv-trampoline/rust-toolchain.toml | 2 +- .../trampolines/uv-trampoline-i686-console.exe | Bin 0 -> 15872 bytes .../trampolines/uv-trampoline-i686-gui.exe | Bin 0 -> 15872 bytes 7 files changed, 32 insertions(+), 7 deletions(-) create mode 100755 crates/uv-trampoline/trampolines/uv-trampoline-i686-console.exe create mode 100755 crates/uv-trampoline/trampolines/uv-trampoline-i686-gui.exe diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af2d95cd0..34a1767bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -266,7 +266,7 @@ jobs: RUSTUP_HOME: ${{ env.DEV_DRIVE }}/.rustup run: | rustup target add x86_64-pc-windows-msvc - rustup component add clippy rust-src --toolchain nightly-2024-03-19-x86_64-pc-windows-msvc + rustup component add clippy rust-src --toolchain nightly-2024-05-27-x86_64-pc-windows-msvc - uses: rui314/setup-mold@v1 diff --git a/crates/install-wheel-rs/src/lib.rs b/crates/install-wheel-rs/src/lib.rs index 6bd39f7c4..9c748e800 100644 --- a/crates/install-wheel-rs/src/lib.rs +++ b/crates/install-wheel-rs/src/lib.rs @@ -70,7 +70,9 @@ pub enum Error { RecordCsv(#[from] csv::Error), #[error("Broken virtualenv: {0}")] BrokenVenv(String), - #[error("Unable to create Windows launcher for {0} (only x64_64 is supported)")] + #[error( + "Unable to create Windows launcher for: {0} (only x86_64, x86, and arm64 are supported)" + )] UnsupportedWindowsArch(&'static str), #[error("Unable to create Windows launcher on non-Windows platform")] NotWindows, diff --git a/crates/install-wheel-rs/src/wheel.rs b/crates/install-wheel-rs/src/wheel.rs index 9f9c52da1..b0ea1397a 100644 --- a/crates/install-wheel-rs/src/wheel.rs +++ b/crates/install-wheel-rs/src/wheel.rs @@ -23,6 +23,14 @@ use crate::{Error, Layout}; const LAUNCHER_MAGIC_NUMBER: [u8; 4] = [b'U', b'V', b'U', b'V']; +#[cfg(all(windows, target_arch = "x86"))] +const LAUNCHER_I686_GUI: &[u8] = + include_bytes!("../../uv-trampoline/trampolines/uv-trampoline-i686-gui.exe"); + +#[cfg(all(windows, target_arch = "x86"))] +const LAUNCHER_I686_CONSOLE: &[u8] = + include_bytes!("../../uv-trampoline/trampolines/uv-trampoline-i686-console.exe"); + #[cfg(all(windows, target_arch = "x86_64"))] const LAUNCHER_X86_64_GUI: &[u8] = include_bytes!("../../uv-trampoline/trampolines/uv-trampoline-x86_64-gui.exe"); @@ -161,6 +169,14 @@ pub(crate) fn windows_script_launcher( } let launcher_bin: &[u8] = match env::consts::ARCH { + #[cfg(all(windows, target_arch = "x86"))] + "x86" => { + if is_gui { + LAUNCHER_I686_GUI + } else { + LAUNCHER_I686_CONSOLE + } + } #[cfg(all(windows, target_arch = "x86_64"))] "x86_64" => { if is_gui { diff --git a/crates/uv-trampoline/README.md b/crates/uv-trampoline/README.md index 06ee577e6..883b2e8ea 100644 --- a/crates/uv-trampoline/README.md +++ b/crates/uv-trampoline/README.md @@ -11,6 +11,7 @@ package manager to install LLD and add the `rustup` targets: ```shell sudo apt install llvm clang lld +rustup target add i686-pc-windows-msvc rustup target add x86_64-pc-windows-msvc rustup target add aarch64-pc-windows-msvc ``` @@ -18,8 +19,9 @@ rustup target add aarch64-pc-windows-msvc Then, build the trampolines for both supported architectures: ```shell -cargo +nightly-2024-03-19 xwin build --release --target x86_64-pc-windows-msvc -cargo +nightly-2024-03-19 xwin build --release --target aarch64-pc-windows-msvc +cargo +nightly-2024-05-27 xwin build --xwin-arch x86 --release --target i686-pc-windows-msvc +cargo +nightly-2024-05-27 xwin build --release --target x86_64-pc-windows-msvc +cargo +nightly-2024-05-27 xwin build --release --target aarch64-pc-windows-msvc ``` ### Cross-compiling from macOS @@ -29,6 +31,7 @@ package manager to install LLVM and add the `rustup` targets: ```shell brew install llvm +rustup target add i686-pc-windows-msvc rustup target add x86_64-pc-windows-msvc rustup target add aarch64-pc-windows-msvc ``` @@ -36,8 +39,9 @@ rustup target add aarch64-pc-windows-msvc Then, build the trampolines for both supported architectures: ```shell -cargo +nightly-2024-03-19 xwin build --release --target x86_64-pc-windows-msvc -cargo +nightly-2024-03-19 xwin build --release --target aarch64-pc-windows-msvc +cargo +nightly-2024-05-27 xwin build --release --target i686-pc-windows-msvc +cargo +nightly-2024-05-27 xwin build --release --target x86_64-pc-windows-msvc +cargo +nightly-2024-05-27 xwin build --release --target aarch64-pc-windows-msvc ``` ### Updating the prebuilt executables @@ -49,6 +53,8 @@ cp target/aarch64-pc-windows-msvc/release/uv-trampoline-console.exe trampolines/ cp target/aarch64-pc-windows-msvc/release/uv-trampoline-gui.exe trampolines/uv-trampoline-aarch64-gui.exe cp target/x86_64-pc-windows-msvc/release/uv-trampoline-console.exe trampolines/uv-trampoline-x86_64-console.exe cp target/x86_64-pc-windows-msvc/release/uv-trampoline-gui.exe trampolines/uv-trampoline-x86_64-gui.exe +cp target/i686-pc-windows-msvc/release/uv-trampoline-console.exe trampolines/uv-trampoline-i686-console.exe +cp target/i686-pc-windows-msvc/release/uv-trampoline-gui.exe trampolines/uv-trampoline-i686-gui.exe ``` ### Testing the trampolines @@ -167,6 +173,7 @@ might not realize that, and still emit references to the unwinding helper exist. ``` +cargo build --release --target i686-pc-windows-msvc cargo build --release --target x86_64-pc-windows-msvc cargo build --release --target aarch64-pc-windows-msvc ``` diff --git a/crates/uv-trampoline/rust-toolchain.toml b/crates/uv-trampoline/rust-toolchain.toml index e51a32bf6..b933c66a7 100644 --- a/crates/uv-trampoline/rust-toolchain.toml +++ b/crates/uv-trampoline/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "nightly-2024-03-19" +channel = "nightly-2024-05-27" diff --git a/crates/uv-trampoline/trampolines/uv-trampoline-i686-console.exe b/crates/uv-trampoline/trampolines/uv-trampoline-i686-console.exe new file mode 100755 index 0000000000000000000000000000000000000000..33de099f42bb49daa79a63a57a78fb4346b527e2 GIT binary patch literal 15872 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 literal 0 HcmV?d00001 diff --git a/crates/uv-trampoline/trampolines/uv-trampoline-i686-gui.exe b/crates/uv-trampoline/trampolines/uv-trampoline-i686-gui.exe new file mode 100755 index 0000000000000000000000000000000000000000..119c4f19d72d3a7da40a2554a0bfe3daa24691f5 GIT binary patch literal 15872 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 Wrv~$0OIEQ^{6z8l*suP*U;hiB=5%%d literal 0 HcmV?d00001