From 13d1a1f6d5ff71067c5efb8ca5e48279a9078957 Mon Sep 17 00:00:00 2001 From: Zsolt Dollenstein Date: Tue, 12 Aug 2025 07:02:58 -0700 Subject: [PATCH 1/2] Windows no std shim (#46) Summary: This PR changes the windows shim to drop a lot of dependencies, shrinking the size of the final binary to 4KB. It's 90% based on zertosh's [work](https://github.com/facebook/dotslash/commit/066d0b3e7c99d0f76fa8249ff3734e44e0906b2d), with a few changes: * stopped using a `Vec` and thus the need for a global allocator * A few extra places for error handling * Updated the dependencies (`windows-sys` and `compiler_builtins`) Pull Request resolved: https://github.com/facebook/dotslash/pull/46 Test Plan: Imported from GitHub, without a `Test Plan:` line. Rollback Plan: Reviewed By: bigfootjon Differential Revision: D69394745 Pulled By: zsol --- website/docs/windows.md | 17 +- windows_shim/Cargo.lock | 83 +++++ windows_shim/Cargo.toml | 8 + windows_shim/README.md | 28 +- windows_shim/dotslash_windows_shim-x86_64.exe | Bin 0 -> 4096 bytes windows_shim/dotslash_windows_shim.rs | 346 ++++++++++++++++-- windows_shim/release.py | 65 ++++ windows_shim/run_test.py | 3 + windows_shim/rust-toolchain.toml | 2 + 9 files changed, 513 insertions(+), 39 deletions(-) create mode 100644 windows_shim/dotslash_windows_shim-x86_64.exe create mode 100644 windows_shim/release.py create mode 100644 windows_shim/rust-toolchain.toml diff --git a/website/docs/windows.md b/website/docs/windows.md index fc3992c..dcbd289 100644 --- a/website/docs/windows.md +++ b/website/docs/windows.md @@ -69,19 +69,22 @@ of this documentation. ### DotSlash Windows Shim -**This is the preferred method.** The _DotSlash Windows Shim_ is a tiny `.exe` -executable that is placed next to the DotSlash file that performs the same -function as the [batch script](#sibling-batch-script) above, but is a native -executable rather than a batch script. This is the _ideal_ method that allows -for easy execution without any of the drawbacks of batch scripts. But this -method requires compiling a small executable and keeping it next to the DotSlash -file. +**This is the preferred method.** The _DotSlash Windows Shim_ is a tiny 4KB +`.exe` executable that is placed next to the DotSlash file that performs the +same function as the [batch script](#sibling-batch-script) above, but is a +native executable rather than a batch script. This is the _ideal_ method that +allows for easy execution without any of the drawbacks of batch scripts. But +this method requires compiling a small executable and keeping it next to the +DotSlash file. The _DotSlash Windows Shim_ is available under the [`windows_shim`](https://github.com/facebook/dotslash/tree/main/windows_shim) folder in the [DotSlash GitHub repository](https://github.com/facebook/dotslash). +A pre-built version can also be downloaded from there: +[`dotslash_windows_shim-x86_64.exe`](https://github.com/facebook/dotslash/raw/main/windows_shim/dotslash_windows_shim-x86_64.exe) + ## `MAX_PATH` limits DotSlash stores fetched artifacts in a cache directory and they're executed from diff --git a/windows_shim/Cargo.lock b/windows_shim/Cargo.lock index 4854961..19082bf 100644 --- a/windows_shim/Cargo.lock +++ b/windows_shim/Cargo.lock @@ -2,6 +2,89 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + [[package]] name = "dotslash_windows_shim" version = "0.0.0" +dependencies = [ + "cfg-if", + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/windows_shim/Cargo.toml b/windows_shim/Cargo.toml index 6f6bb67..7b2e7c5 100644 --- a/windows_shim/Cargo.toml +++ b/windows_shim/Cargo.toml @@ -14,6 +14,14 @@ name = "dotslash_windows_shim" path = "dotslash_windows_shim.rs" test = false +[dependencies] +cfg-if = "1.0.1" +windows-sys = { version = "0.59.0", features = ["Win32_Foundation", "Win32_Globalization", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Console", "Win32_System_Environment", "Win32_System_IO", "Win32_System_LibraryLoader", "Win32_System_Memory", "Win32_System_Threading", "Win32_UI_Shell"] } + +[features] +default = ["no_std"] +no_std = [] + [profile.release] opt-level = "z" lto = true diff --git a/windows_shim/README.md b/windows_shim/README.md index 92bae85..4194e1f 100644 --- a/windows_shim/README.md +++ b/windows_shim/README.md @@ -24,5 +24,29 @@ The _DotSlash Windows Shim_ does this: ## Binary size -The current "reference implementation" is rather large. A no_std version that -uses only Windows APIs will be added soon. Stay tuned! +_DotSlash Windows Shim_ builds without a standard library and only uses Windows +APIs. Release binaries are around ~5KB. + +## Release + +A nightly toolchain is required: + +```shell +cargo +nightly build --release +``` + +Alternatively, though not recommended: + +```shell +RUSTC_BOOTSTRAP=1 cargo build --release +``` + +## Debugging + +It may be useful to have the standard library (e.g. `dbg!`) when debugging. +Build with `--no-default-features` (avoids the default `no_std` feature) to have +access to the standard library. + +```shell +cargo build --no-default-features +``` diff --git a/windows_shim/dotslash_windows_shim-x86_64.exe b/windows_shim/dotslash_windows_shim-x86_64.exe new file mode 100644 index 0000000000000000000000000000000000000000..cbfa4e3c9256a020fa74cfdc7928f615ec173b30 GIT binary patch literal 4096 zcmeHKU2GIp6h7M)C`h}7X8l3HX;~9$=w{2GKzL|rivwAt($YoP=1m^QZ#B(iqXXA1DjB_A`c*u@jEkjDbbb~o-lIT zd(XMw`MKwwIrsK<+pZH-OhhHM=D?RyNNsTxX>X*XtVEj!*TS$E(GB9q6Yc z?R`Pe9f@e1b!LjFrI{#pw3vQ<@1yR5&LmaSGezaEIGZbV(YckN6%JqTVZwY7(QF5r zqD}%hDQLwMIaDwbwm@Ac1;Tm)VU|`eBWiItF$9S=K0FuvXcf`oY48~#iRjFXLZX1F z?l&Q?gVx5~MRplprF)|YaBhkr$G8J)XrqxpiUA2}EEOC($8W$TXyYjTTq z-S*|ZL?`6jrQq&2_grib!+v?ezN`Z_L(gG<`48Yiw(iQ-t^E7U_LqfO=3&`U0Oy#q zeHYD#_%*>nHr{)3pw z)*Lz4U5dHy3d7dj{7!b;_iCuGr*v!o#(i~HY~KXV!e{ppUa02xLYBsD-}iv63rB{% zCx_+r-*``+KYTg603mMR5EsFF{?dKh-r^YxS%dy#yqbLhE7(2_hPgW)?>m)9kAvI- zV*5^Ggn!$26HHfb9hu1a2x4n+LLT%VWGB{d`A^^%6p6}z$ZX$QZ+KYlKkPpN1#b<0 z>s!$4(Svd>5@A3>uNa{?yXX)3Biu>XS>|i^L3Z;; zFaxaQeEQu`0H^yss9|6|fKjgE{I|>j`v0^Gg+Ih%%bjAL5>yuST|ox~ zJuPUjplyP#6LeD0y)V0t7YgbZG$`n1K|2I3Wd1v0U-UOTrkfc}$;4}W5~-Nplc~+b z6UhzIyo_liQr%KiPem0|O(|wVPf1-$LQ`X#vRz%OA?f>6qf66!Vx*Hv8PZ6>7$*r! za*yg+Ehh1cMcuDPv!*H))`Hh$Qc1-E4**v~>C{xmpi9p}I_02SHUD7@uL%>L@caoY z33Ib8_ZY7*f#@5fFuQyU4qrkdOISXNUvV_&Z;Ni|%s zL;P+lynk>eXq=&H^m#-H@+x zeY$i1K3y}DF;>KSe7_33x3@Re$q%wS!1)ak*zdk4_s6!`qvG~e?Q z%?g&Jiz7upcuG7}vWaK_F%?=b>a#*}<1ApuxMqP#h_lc>1~vd}ruJVuhsh!oW2+gH zaV|8K=!IEfBVjs)NeeyAsPz^@kE)prZJedyaB6BQOtjMBaYDgwXAeS2R+Ti-Pen`{ zG)<3EB}?66cb9;LcM5xO0D#i;hlZ%vk-U-BO|>K;DO&p_dJIZDK$(XM+<0! z(ajpCsL@byhltRC+;HOBY^d1h&n45GUb@C!dDD$J--V4+6E$jjMinW#$2uV;V>TOx zZV>w%7|JW~-p4qky* p5IUbvrbp3BP~S`^&?~?*<^P)&gJ)WazT%-X@HoppwRti!@E7B?r5*qP literal 0 HcmV?d00001 diff --git a/windows_shim/dotslash_windows_shim.rs b/windows_shim/dotslash_windows_shim.rs index 8281150..d05b2cf 100644 --- a/windows_shim/dotslash_windows_shim.rs +++ b/windows_shim/dotslash_windows_shim.rs @@ -8,36 +8,322 @@ * above-listed licenses. */ -//! This is the "DotSlash Windows Shim" using Rust's standard library. -//! Unfortunately even with an optimized libstd, the resulting binary is -//! too large for comfortably checking into source control. -//! -//! This implementation serves as a "Reference Implementation" for the -//! upcoming no_std pure-Windows-API version. - -use std::env; -use std::io; -use std::process::Command; - -fn main() { - let exe_path = - env::current_exe().expect("dotslash-windows-shim: could not get module filename."); - let filename = exe_path.file_stem().unwrap(); - let exe_path = exe_path.with_file_name(filename); - - let mut command = Command::new("dotslash"); - command.arg(exe_path); - command.args(env::args_os().skip(1)); - - match command.status() { - Ok(exit_code) => std::process::exit(exit_code.code().unwrap_or(1)), - Err(err) => { - if err.kind() == io::ErrorKind::NotFound { - eprintln!("dotslash-windows-shim: dotslash executable not found."); - } else { - eprintln!("dotslash-windows-shim: `{}`.", err); - }; - std::process::exit(1); +//! The "DotSlash Windows Shim" is a tiny executable (.exe) to workaround +//! Windows' lack of shebang support. The shim is placed next to a DotSlash +//! file (with the DotSlash filename plus `.exe`) and it runs the DotSlash +//! file and forwards all arguments and IO streams. + +//! This code is optimized for size since the shim is meant to be checked +//! into source control for every DotSlash file that needs to be run on +//! Windows. Only Windows APIs are used to avoid increasing binary size. + +#![cfg_attr(feature = "no_std", allow(internal_features))] +#![cfg_attr(feature = "no_std", feature(core_intrinsics))] +#![cfg_attr(feature = "no_std", feature(lang_items))] +#![cfg_attr(feature = "no_std", no_std)] +#![cfg_attr(feature = "no_std", no_main)] +#![cfg_attr(feature = "no_std", windows_subsystem = "console")] // Set Entrypoint to "mainCRTStartup" + +#[allow(clippy::upper_case_acronyms)] +type DWORD = u32; + +use core::mem; +use core::ptr; +use core::str; + +use windows_sys::Win32::Foundation::BOOL; +use windows_sys::Win32::Foundation::CloseHandle; +use windows_sys::Win32::Foundation::ERROR_FILE_NOT_FOUND; +use windows_sys::Win32::Foundation::GetLastError; +use windows_sys::Win32::Foundation::HANDLE; +use windows_sys::Win32::Foundation::HMODULE; +use windows_sys::Win32::Foundation::S_FALSE; +use windows_sys::Win32::Foundation::S_OK; +use windows_sys::Win32::Foundation::TRUE; +use windows_sys::Win32::Foundation::WAIT_OBJECT_0; +use windows_sys::Win32::Globalization::lstrcatW; +use windows_sys::Win32::Globalization::lstrlenW; +use windows_sys::Win32::Storage::FileSystem::WriteFile; +use windows_sys::Win32::System::Console::GetStdHandle; +use windows_sys::Win32::System::Console::STD_ERROR_HANDLE; +use windows_sys::Win32::System::Environment::GetCommandLineW; +use windows_sys::Win32::System::LibraryLoader::GetModuleFileNameW; +use windows_sys::Win32::System::LibraryLoader::GetModuleHandleW; +use windows_sys::Win32::System::Memory::GetProcessHeap; +use windows_sys::Win32::System::Memory::HEAP_ZERO_MEMORY; +use windows_sys::Win32::System::Memory::HeapAlloc; +use windows_sys::Win32::System::Memory::HeapFree; +use windows_sys::Win32::System::Threading::CreateProcessW; +use windows_sys::Win32::System::Threading::ExitProcess; +use windows_sys::Win32::System::Threading::GetExitCodeProcess; +use windows_sys::Win32::System::Threading::INFINITE; +use windows_sys::Win32::System::Threading::PROCESS_INFORMATION; +use windows_sys::Win32::System::Threading::STARTUPINFOW; +use windows_sys::Win32::System::Threading::WaitForSingleObject; +use windows_sys::Win32::UI::Shell::PathCchRemoveExtension; +use windows_sys::Win32::UI::Shell::PathGetArgsW; +use windows_sys::Win32::UI::Shell::PathQuoteSpacesW; +use windows_sys::core::PCWSTR; +use windows_sys::core::PWSTR; +use windows_sys::w; + +fn write_stderr(text: &str) -> BOOL { + // lpNumberOfBytesWritten can be NULL only when the lpOverlapped + // parameter is not NULL. + let mut bytes_written: u32 = 0; + unsafe { + let stdout: HANDLE = GetStdHandle(STD_ERROR_HANDLE); + let ok: BOOL = WriteFile( + stdout, /* hFile */ + text.as_ptr(), /* lpBuffer */ + text.len() as u32, /* nNumberOfBytesToWrite */ + &mut bytes_written as *mut u32, /* lpNumberOfBytesWritten */ + ptr::null_mut(), /* lpOverlapped */ + ); + ok + } +} + +fn fatal(text: &str) -> ! { + write_stderr("dotslash-windows-shim: "); + write_stderr(text); + write_stderr("\n"); + unsafe { ExitProcess(1) } +} + +// CreateProcessW's lpCommandLine has a maximum length of 32,767 +// characters. +const BUF_MAX_SIZE: usize = 32767; + +struct PoorMansString { + buf: *mut u16, + len: usize, +} + +impl PoorMansString { + fn append(&mut self, other: *const u16) { + let other_len = unsafe { lstrlenW(other) as usize }; + if self.len + other_len > BUF_MAX_SIZE { + fatal("Buffer overflow"); + } + unsafe { + // Concatenate other string to self.buf + if lstrcatW(self.buf, other).is_null() { + fatal("string concatenation failed"); + } + } + + self.len = self.len + other_len; + } + + fn capacity(&self) -> usize { + BUF_MAX_SIZE - 1 + } + + fn new() -> Self { + // Allocate BUF_MAX_SIZE upfront to avoid growing buffers. + let buf = unsafe { + HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + BUF_MAX_SIZE * mem::size_of::(), + ) as *mut u16 + }; + Self { buf, len: 0 } + } +} + +impl Drop for PoorMansString { + fn drop(&mut self) { + unsafe { + HeapFree(GetProcessHeap(), 0, self.buf as *mut _); } } } + +fn main_impl() -> ! { + let mut ds_cmd = PoorMansString::new(); + + // Append "dotslash " to the command string. + ds_cmd.append(w!("dotslash ")); + + // Append the DotSlash file path to the command string. + // + // NOTE: Turning this executable's full path into a valid argument on the + // command string will happen in-place in the command string. + unsafe { + let ds_file_ptr = ds_cmd.buf.add(ds_cmd.len); + // Get a handle to this executable. + // + // When passed NULL, GetModuleHandle returns a handle to the file + // used to create the calling process (.exe file). + let handle: HMODULE = GetModuleHandleW(ptr::null_mut()); + + // Append the fully qualified path for this executable to the + // command string. + // + // For an executable named `foo.exe` we should now have a command + // string that looks like `dotslash C:\path\to\foo.exe`. + // + // GetModuleFileName requires you to keep growing a buffer until it + // fits the path. No need to do this because the command buffer + // is already as large as can be. + let remaining_capacity = ds_cmd.capacity() - ds_cmd.len; + let new_len = GetModuleFileNameW( + handle, /* hModule */ + ds_file_ptr, /* lpFilename */ + remaining_capacity as _, /* nSize */ + ) as usize; + if new_len == 0 || new_len == remaining_capacity { + fatal("GetModuleFileNameW failed."); + } + ds_cmd.len += new_len; + + // Remove the extension from this executable's full path. + // + // We assume that the DotSlash file is named just like this executable but + // without the `.exe`. + // + // For an executable named `foo.exe` we should now have a command string that + // looks like `dotslash C:\path\to\foo`. + // + // PathCchRemoveExtension returns `S_OK` when an extension was found and + // removed. It returns `S_FALSE` when there is no extension. In this case, we'll + // pass this executable as the DotSlash file path. `dotslash` will fail and + // complain that it's not a valid DotSlash file. + // + let found_extension = PathCchRemoveExtension(ds_file_ptr, new_len + 1); + if found_extension != S_OK && found_extension != S_FALSE { + fatal("PathCchRemoveExtension failed."); + } + + // Quote the entire DotSlash file path if there are spaces. + // + // No need to worry about escaping quotes because those aren't + // allowed in Windows paths. + // + // For an executable named `foo.exe` this is a noop. + // + // For an executable named `foo bar.exe` we should now have a command + // string that looks like `dotslash "C:\path\to\foo bar"`. + PathQuoteSpacesW(ds_file_ptr); + + // Get the arguments that were passed to us. + let line_ptr: PCWSTR = GetCommandLineW(); + // Skip `argv[0]` and focus on the remaining arguments. + let args_ptr: PWSTR = PathGetArgsW(line_ptr); + // Append the arguments to the command string if there are any. + if *args_ptr != 0 { + // Append a separator for the arguments. + ds_cmd.append(w!(" ")); + ds_cmd.append(args_ptr); + } + } + + // Run the command string. + + let mut si: STARTUPINFOW = unsafe { mem::zeroed() }; + si.cb = mem::size_of::() as DWORD; + let mut pi: PROCESS_INFORMATION = unsafe { mem::zeroed() }; + + let status = unsafe { + CreateProcessW( + ptr::null_mut(), // lpApplicationName + ds_cmd.buf, // lpCommandLine + ptr::null_mut(), // lpProcessAttributes + ptr::null_mut(), // lpThreadAttributes + TRUE, // bInheritHandles + 0, // dwCreationFlags + ptr::null_mut(), // lpEnvironment + ptr::null_mut(), // lpCurrentDirectory + &si, + &mut pi, + ) + }; + + // Once CreateProcessW is called, there is no need to hold onto + // lpCommandLine. + // https://stackoverflow.com/a/31031165 + drop(ds_cmd); + + if status == TRUE { + let res = unsafe { WaitForSingleObject(pi.hProcess, INFINITE) }; + if res != WAIT_OBJECT_0 { + fatal("WaitForSingleObject failed."); + } + + let mut status = 0; + let res = unsafe { GetExitCodeProcess(pi.hProcess, &mut status) }; + if res != TRUE { + fatal("could not get dotslash command exit code."); + } + + unsafe { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + ExitProcess(status) + }; + } + + let err = unsafe { GetLastError() }; + if err == ERROR_FILE_NOT_FOUND { + fatal("dotslash executable not found."); + } + + fatal("could not execute dotslash command."); +} + +#[cfg(not(feature = "no_std"))] +fn main() -> ! { + main_impl() +} + +// TODO: get rid of this and stop linking to msvcrt +#[cfg(fbcode_build)] +#[unsafe(no_mangle)] +pub extern "C" fn main() -> ! { + main_impl() +} + +#[cfg(all(feature = "no_std", not(fbcode_build)))] +#[unsafe(no_mangle)] +pub extern "C" fn mainCRTStartup() -> ! { + main_impl() +} + +// +// Abort handling +// + +// https://github.com/rust-lang/rust/issues/62785 + +#[panic_handler] +#[cfg(feature = "no_std")] +fn panic(_info: &core::panic::PanicInfo<'_>) -> ! { + // https://github.com/rust-lang/rust/blob/1.75.0/library/panic_abort/src/lib.rs#L58-L83 + #[cfg(windows)] + unsafe { + // https://learn.microsoft.com/en-us/cpp/intrinsics/fastfail + const FAST_FAIL_FATAL_APP_EXIT: usize = 7; + cfg_if::cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + core::arch::asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT); + core::intrinsics::unreachable(); + } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { + core::arch::asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT); + core::intrinsics::unreachable(); + } else if #[cfg(target_arch = "aarch64")] { + core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT); + core::intrinsics::unreachable(); + } + } + } + + // For the benefit of check builds on non-Windows. + #[cfg(not(windows))] + core::intrinsics::abort(); +} + +#[lang = "eh_personality"] +#[cfg(feature = "no_std")] +unsafe extern "C" fn rust_eh_personality() {} diff --git a/windows_shim/release.py b/windows_shim/release.py new file mode 100644 index 0000000..224a8ad --- /dev/null +++ b/windows_shim/release.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is dual-licensed under either the MIT license found in the +# LICENSE-MIT file in the root directory of this source tree or the Apache +# License, Version 2.0 found in the LICENSE-APACHE file in the root directory +# of this source tree. You may select, at your option, one of the +# above-listed licenses. + + +import os +import shutil +import subprocess +from pathlib import Path + +IS_WINDOWS: bool = os.name == "nt" + + +def main() -> None: + if not IS_WINDOWS: + raise Exception("Only Windows is supported.") + + dotslash_windows_shim_root = Path(os.path.realpath(__file__)).parent + + target_dir = ( + Path(os.environ["CARGO_TARGET_DIR"]) + if "CARGO_TARGET_DIR" in os.environ + else None + ) + + subprocess.run( + [ + "cargo", + "build", + "--quiet", + "--manifest-path", + str(dotslash_windows_shim_root / "Cargo.toml"), + "--bin=dotslash_windows_shim", + "--release", + "--target=x86_64-pc-windows-msvc", + ], + check=True, + env={ + **os.environ, + "RUSTC_BOOTSTRAP": "1", + "RUSTFLAGS": "-Clink-arg=/DEBUG:NONE", # Avoid embedded pdb path + }, + ) + + src = ( + ( + target_dir + or (dotslash_windows_shim_root / "target" / "x86_64-pc-windows-msvc") + ) + / "release" + / "dotslash_windows_shim.exe" + ) + + dest = dotslash_windows_shim_root / "dotslash_windows_shim-x86_64.exe" + + shutil.copy(src, dest) + + +if __name__ == "__main__": + main() diff --git a/windows_shim/run_test.py b/windows_shim/run_test.py index 54516d7..5b08401 100755 --- a/windows_shim/run_test.py +++ b/windows_shim/run_test.py @@ -56,8 +56,11 @@ def main() -> None: str(dotslash_windows_shim_root / "Cargo.toml"), "--bin=dotslash_windows_shim", "--release", + # UNCOMMENT to compile allowing std use - useful for debugging. + # "--no-default-features", ], check=True, + env={**os.environ, "RUSTC_BOOTSTRAP": "1"}, ) os.environ["DOTSLASH_WINDOWS_SHIM"] = str( (target_dir or (dotslash_windows_shim_root / "target")) diff --git a/windows_shim/rust-toolchain.toml b/windows_shim/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/windows_shim/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" From e2c6fc5789961b1d798ad1201a38e0847f106494 Mon Sep 17 00:00:00 2001 From: Zsolt Dollenstein Date: Tue, 12 Aug 2025 15:11:54 +0100 Subject: [PATCH 2/2] Add arm64 binary too --- .../dotslash_windows_shim-aarch64.exe | Bin 0 -> 4096 bytes windows_shim/dotslash_windows_shim-x86_64.exe | Bin 4096 -> 4096 bytes windows_shim/release.py | 61 ++++++++++-------- 3 files changed, 34 insertions(+), 27 deletions(-) create mode 100644 windows_shim/dotslash_windows_shim-aarch64.exe diff --git a/windows_shim/dotslash_windows_shim-aarch64.exe b/windows_shim/dotslash_windows_shim-aarch64.exe new file mode 100644 index 0000000000000000000000000000000000000000..4f33d81fe595e8fe2c29603d41bacd1436c755a7 GIT binary patch literal 4096 zcmeGfTTB#J^vupeMhN&oL=z3OiVYHXqlhLY)D9w)5ER^{#k3|e><;YO*&Uo63Pn@b z>PI6@>hz_ndRjoxQv7<+H#8fE#Bf18@l;4T-IfUq(@!U;ITrTwFHhxx_V&d0N7exY(s@ zow^(qgK{jU8DhI4>fJFh5)=0}1;nTpQha%NIVHC1lW$c1@@;X;nT7e{nF*U7LzsKy zrT%LO{gGgpbe4*!xfUQa$ivl!kHU`5ZP*C8uKW!wIl)3I9|k^L`5bO!5VT zzah?K>v_`y3IDH1(_SLt!e%K=d(Q>FO5V+d^!x*iH3%lj=g?;geGAK^^c_3KaJG~# zydw4w{N429TO52&dTlN#&0@~8eBs5v*qu$js?n#Eo(p`#VrDVC&6|^4!hhX~N#sqL zPx!w_dM@x~^6o2K@?HVix{~vsV$Dvu#@FB;6C0)Uh|8)GhxS)9=lnvUwO{H4m*h~# zGs>GOtkW3zI$WKk*o1XbI)ybfvWxmD&(X{~eu}k_EBcPfH&C4m%Sa~WLd7i}%7$IS zAE_K@nRN;MTo#yA$JynOUWWd*a8g=C-C{Q!tw$a5L2_ZA6$|s}U4$QSaOw4W4l3xJ zSgdQ^EY?pjR*IQoI!AG1y33=C85gRvS8*e`f3b;ON_ekY>bHIUe@*L}DSW zC+>}hBhgARCvNDGSf?1&VnNwZVzLp@Vq%9JQI*i1?v4&c7q!GaZo|V zHOzkeMD!liy48?KFBYX&33eNb=I^lIu+wz#^^O- zpeKC(w8{~qPSXPzu&Ok*A5nsa9jdQcHo`T*uwRK{xV62QNqiv@-wTSdPYZRcN*(64 zUydrRjvcFx^Y+O@Y6Rzu2Pb|M*ub{{y$PK60i{jv2w#ML-%ECq4t{WH z@-4cgudgrE-ih?Jjn)souh)7T&|9a9^ekWHh=PQ?wF|r*#5;(*MSE5dkNV{}?P=NW zA|Bv7qZEPj_F%lnENh@`-IQxj$qa{cdU|>_zI+&sxCf*ag^++LzUKOy&&*7}N3yKi zarceV87zk|d2(htjBz=m0sC-;XvOOA4pMI-@Ae|SUgUj%yrssIcCVr?Y_5P2s>eQ8 z6@YbFt$M^@jRvc@TI}6sT?;DlI8OTh70mNb_akm2{7hac=^DJRPU5f^YE&(**d=;EI*oGNsMU2% z2Y6M{V~VkKd&Uj*SBV#?|n$3(%|5@vIsW6~`C@4P- zN;^R57AQRdN-u%ZMNrxYN*h4w7f?D$6=FOWl$L?g8W38U!44`A0;OTDxdJudm&)cv z99oPDAU}ZQc!Br^5dTpGVonAI36Nj|L&HQx(aEe_>h&g!3=DcjDTyVC3=B_zYC!T3 zzDiksPDySGRPPUjcvV$ZN>VzI|3!&`!3HE=0nu-u4CQBn_$o#~DTW-NmM9df@ z)&LaS01=zKnu`+{&Re(Ra|dbwlj`P0 z99oQE9>^acd0rsC0b(ctF&6`a1c=?h&@fR^bTT8Cx|#(e1A|^sN@7VO1H%hNh&+U^ zQkI`nlA8ijuQb_@OU(BN&lz6T)S_&{Q vI07*!{6KUY5VHV%4x--xu>g<_qB(^b7-WEK5G@SEI?9_J`SvqTG++k+XPsAv diff --git a/windows_shim/release.py b/windows_shim/release.py index 224a8ad..97cd59c 100644 --- a/windows_shim/release.py +++ b/windows_shim/release.py @@ -15,6 +15,10 @@ IS_WINDOWS: bool = os.name == "nt" +target_triplets: list[str] = [ + "x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc" +] + def main() -> None: if not IS_WINDOWS: @@ -28,37 +32,40 @@ def main() -> None: else None ) - subprocess.run( - [ - "cargo", - "build", - "--quiet", - "--manifest-path", - str(dotslash_windows_shim_root / "Cargo.toml"), - "--bin=dotslash_windows_shim", - "--release", - "--target=x86_64-pc-windows-msvc", - ], - check=True, - env={ - **os.environ, - "RUSTC_BOOTSTRAP": "1", - "RUSTFLAGS": "-Clink-arg=/DEBUG:NONE", # Avoid embedded pdb path - }, - ) + for triplet in target_triplets: + subprocess.run( + [ + "cargo", + "build", + "--quiet", + "--manifest-path", + str(dotslash_windows_shim_root / "Cargo.toml"), + "--bin=dotslash_windows_shim", + "--release", + f"--target={triplet}", + ], + check=True, + env={ + **os.environ, + "RUSTC_BOOTSTRAP": "1", + "RUSTFLAGS": "-Clink-arg=/DEBUG:NONE", # Avoid embedded pdb path + }, + ) - src = ( - ( - target_dir - or (dotslash_windows_shim_root / "target" / "x86_64-pc-windows-msvc") + src = ( + ( + target_dir + or (dotslash_windows_shim_root / "target" / triplet) + ) + / "release" + / "dotslash_windows_shim.exe" ) - / "release" - / "dotslash_windows_shim.exe" - ) - dest = dotslash_windows_shim_root / "dotslash_windows_shim-x86_64.exe" + arch = triplet.partition('-')[0] + + dest = dotslash_windows_shim_root / f"dotslash_windows_shim-{arch}.exe" - shutil.copy(src, dest) + shutil.copy(src, dest) if __name__ == "__main__":