Skip to content

Commit 1ccb474

Browse files
authored
chore: support for Windows ARM64 (#174)
This PR add support for Windows ARM64. Since there is no dedicated Solidity version for Windows ARM64 it use the x86 version. Which seems to work fine using x86 emulation. I was undecided about removing the `target_arch` for Windows altogether, but I kept it to mark it as a tested variant. **Before this PR:** During the build it was trying to fetch "https://binaries.soliditylang.org/Unsupported-platform/list.json" (there is no further error handling if the request fails): ``` PS C:\Users\cakevm\Documents\projects\rust\svm-rs> cargo build Compiling svm-rs-builds v0.5.19 (C:\Users\cakevm\Documents\projects\rust\svm-rs\crates\svm-builds) error: failed to run custom build command for `svm-rs-builds v0.5.19 (C:\Users\cakevm\Documents\projects\rust\svm-rs\crates\svm-builds)` Caused by: process didn't exit successfully: `C:\Users\cakevm\Documents\projects\rust\svm-rs\target\debug\build\svm-rs-builds-34686cb3a1738671\build-script-build` (exit code: 101) --- stderr thread 'main' (5676) panicked at crates\svm-builds\build.rs:150:46: Failed to fetch releases: ReqwestError(reqwest::Error { kind: Decode, source: Error("expected value", line: 1, column: 1) }) note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ```
1 parent 0956880 commit 1ccb474

File tree

8 files changed

+83
-13
lines changed

8 files changed

+83
-13
lines changed

crates/svm-rs/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ tokio = { version = "1", features = [
5757
"macros",
5858
], optional = true }
5959

60-
[target.'cfg(all(target_os = "windows", target_arch = "x86_64"))'.dependencies]
60+
[target.'cfg(target_os = "windows")'.dependencies]
6161
zip = { version = "4", default-features = false, features = ["deflate"] }
6262

6363
[dev-dependencies]

crates/svm-rs/src/bin/solc/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
)]
77
#![warn(rustdoc::all)]
88
#![deny(unused_must_use, rust_2018_idioms)]
9-
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
9+
#![cfg_attr(docsrs, feature(doc_cfg))]
1010

1111
use anyhow::Context;
1212
use std::io;

crates/svm-rs/src/bin/svm-bin/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
)]
77
#![warn(rustdoc::all)]
88
#![deny(unused_must_use, rust_2018_idioms)]
9-
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
9+
#![cfg_attr(docsrs, feature(doc_cfg))]
1010

1111
use clap::Parser;
1212

crates/svm-rs/src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub enum SvmError {
3636
UrlError(#[from] url::ParseError),
3737
#[error("Received unsuccessful response with code {1} for {0}")]
3838
UnsuccessfulResponse(Url, StatusCode),
39-
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
39+
#[cfg(target_os = "windows")]
4040
#[error(transparent)]
4141
ZipError(#[from] zip::result::ZipError),
4242
}

crates/svm-rs/src/install.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ fn do_install(version: &Version, binbytes: &[u8], _artifact: &str) -> Result<Pat
161161
let installer = Installer { version, binbytes };
162162

163163
// Solc versions <= 0.7.1 are .zip files for Windows only
164-
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
164+
#[cfg(target_os = "windows")]
165165
if _artifact.ends_with(".zip") {
166166
return installer.install_zip();
167167
}
@@ -243,7 +243,7 @@ impl Installer<'_> {
243243

244244
/// Extracts the solc archive at the version specified destination and returns the path to the
245245
/// installed solc binary.
246-
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
246+
#[cfg(target_os = "windows")]
247247
fn install_zip(self) -> Result<PathBuf, SvmError> {
248248
let solc_path = version_binary(&self.version.to_string());
249249
let version_path = solc_path.parent().unwrap();
@@ -328,17 +328,33 @@ mod tests {
328328
} else {
329329
"which"
330330
};
331+
// Long-running command: `sleep infinity` on Unix, `timeout /t 3600` on Windows
332+
const CMD: &str = if cfg!(target_os = "windows") {
333+
"timeout"
334+
} else {
335+
"sleep"
336+
};
331337

332338
let version: Version = "0.8.10".parse().unwrap();
333339
let solc_path = version_binary(version.to_string().as_str());
334340

335341
fs::create_dir_all(solc_path.parent().unwrap()).unwrap();
336342

337-
// Overwrite solc with `sleep` and call it with `infinity`.
338-
let stdout = Command::new(WHICH).arg("sleep").output().unwrap().stdout;
339-
let sleep_path = String::from_utf8(stdout).unwrap();
340-
fs::copy(sleep_path.trim_end(), &solc_path).unwrap();
341-
let mut child = Command::new(solc_path).arg("infinity").spawn().unwrap();
343+
// Overwrite solc with a long-running command.
344+
let stdout = Command::new(WHICH).arg(CMD).output().unwrap().stdout;
345+
let cmd_path = String::from_utf8(stdout).unwrap();
346+
// On Windows, `where` can return multiple paths - take the first one
347+
let cmd_path = cmd_path.lines().next().unwrap_or(&cmd_path);
348+
fs::copy(cmd_path.trim_end(), &solc_path).unwrap();
349+
350+
let mut child = if cfg!(target_os = "windows") {
351+
Command::new(&solc_path)
352+
.args(["/t", "3600"])
353+
.spawn()
354+
.unwrap()
355+
} else {
356+
Command::new(&solc_path).arg("infinity").spawn().unwrap()
357+
};
342358

343359
// Install should not fail with "text file busy".
344360
install(&version).await.unwrap();
@@ -458,7 +474,7 @@ mod tests {
458474
}
459475

460476
#[tokio::test]
461-
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
477+
#[cfg(target_os = "windows")]
462478
async fn can_install_windows_zip_release() {
463479
let version = "0.7.1".parse().unwrap();
464480
install(&version).await.unwrap();

crates/svm-rs/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
warn(unused_crate_dependencies)
1010
)]
1111
#![deny(unused_must_use, rust_2018_idioms)]
12-
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
12+
#![cfg_attr(docsrs, feature(doc_cfg))]
1313

1414
use semver::Version;
1515
use std::fs;

crates/svm-rs/src/platform.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub enum Platform {
1111
MacOsAmd64,
1212
MacOsAarch64,
1313
WindowsAmd64,
14+
WindowsAarch64,
1415
AndroidAarch64,
1516
Unsupported,
1617
}
@@ -23,6 +24,7 @@ impl fmt::Display for Platform {
2324
Self::MacOsAmd64 => "macosx-amd64",
2425
Self::MacOsAarch64 => "macosx-aarch64",
2526
Self::WindowsAmd64 => "windows-amd64",
27+
Self::WindowsAarch64 => "windows-aarch64",
2628
Self::AndroidAarch64 => "android-aarch64",
2729
Self::Unsupported => "Unsupported-platform",
2830
};
@@ -40,6 +42,7 @@ impl FromStr for Platform {
4042
"macosx-amd64" => Ok(Self::MacOsAmd64),
4143
"macosx-aarch64" => Ok(Self::MacOsAarch64),
4244
"windows-amd64" => Ok(Self::WindowsAmd64),
45+
"windows-aarch64" => Ok(Self::WindowsAarch64),
4346
"android-aarch64" => Ok(Self::AndroidAarch64),
4447
s => Err(format!("unsupported platform {s}")),
4548
}
@@ -61,6 +64,7 @@ pub fn platform() -> Platform {
6164
("macos", "x86_64") => Platform::MacOsAmd64,
6265
("macos", "aarch64") => Platform::MacOsAarch64,
6366
("windows", "x86_64") => Platform::WindowsAmd64,
67+
("windows", "aarch64") => Platform::WindowsAarch64,
6468
("android", "aarch64") => Platform::AndroidAarch64,
6569
_ => Platform::Unsupported,
6670
}
@@ -100,6 +104,12 @@ mod tests {
100104
assert_eq!(platform(), Platform::WindowsAmd64);
101105
}
102106

107+
#[test]
108+
#[cfg(all(target_os = "windows", target_arch = "aarch64"))]
109+
fn get_platform() {
110+
assert_eq!(platform(), Platform::WindowsAarch64);
111+
}
112+
103113
#[test]
104114
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
105115
fn get_platform() {

crates/svm-rs/src/releases.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,16 @@ pub fn blocking_all_releases(platform: Platform) -> Result<Releases, SvmError> {
166166
Platform::AndroidAarch64 => {
167167
Ok(reqwest::blocking::get(ANDROID_AARCH64_RELEASES_URL)?.json::<Releases>()?)
168168
}
169+
Platform::WindowsAarch64 => {
170+
// Windows ARM64 uses x64 binaries via emulation
171+
// Solidity does not provide native ARM64 Windows binaries
172+
let releases = reqwest::blocking::get(format!(
173+
"{SOLC_RELEASES_URL}/{}/list.json",
174+
Platform::WindowsAmd64
175+
))?
176+
.json::<Releases>()?;
177+
Ok(unified_releases(releases, platform))
178+
}
169179
_ => {
170180
let releases =
171181
reqwest::blocking::get(format!("{SOLC_RELEASES_URL}/{platform}/list.json"))?
@@ -217,6 +227,19 @@ pub async fn all_releases(platform: Platform) -> Result<Releases, SvmError> {
217227
.await?
218228
.json::<Releases>()
219229
.await?),
230+
Platform::WindowsAarch64 => {
231+
// Windows ARM64 uses x64 binaries via emulation
232+
// Solidity does not provide native ARM64 Windows binaries
233+
let releases = get(format!(
234+
"{SOLC_RELEASES_URL}/{}/list.json",
235+
Platform::WindowsAmd64
236+
))
237+
.await?
238+
.json::<Releases>()
239+
.await?;
240+
241+
Ok(unified_releases(releases, platform))
242+
}
220243
_ => {
221244
let releases = get(format!("{SOLC_RELEASES_URL}/{platform}/list.json"))
222245
.await?
@@ -305,6 +328,15 @@ pub(crate) fn artifact_url(
305328
}
306329
}
307330

331+
if platform == Platform::WindowsAarch64 {
332+
// Windows ARM64 uses x64 binaries via emulation
333+
// Solidity does not provide native ARM64 Windows binaries
334+
return Ok(Url::parse(&format!(
335+
"{SOLC_RELEASES_URL}/{}/{artifact}",
336+
Platform::WindowsAmd64,
337+
))?);
338+
}
339+
308340
Ok(Url::parse(&format!(
309341
"{SOLC_RELEASES_URL}/{platform}/{artifact}"
310342
))?)
@@ -376,6 +408,18 @@ mod tests {
376408
assert!(all_releases(Platform::LinuxAarch64).await.is_ok());
377409
}
378410

411+
#[tokio::test]
412+
async fn test_all_releases_windows_aarch64() {
413+
let releases = all_releases(Platform::WindowsAarch64).await;
414+
assert!(releases.is_ok());
415+
// Check also that we got the windows-amd64 release
416+
let releases = releases.unwrap();
417+
let latest = releases.releases.keys().max().unwrap();
418+
let artifact = releases.get_artifact(latest).unwrap();
419+
let url = artifact_url(Platform::WindowsAarch64, latest, artifact).unwrap();
420+
assert!(url.to_string().contains("windows-amd64"));
421+
}
422+
379423
#[tokio::test]
380424
async fn releases_roundtrip() {
381425
let releases = all_releases(Platform::LinuxAmd64).await.unwrap();

0 commit comments

Comments
 (0)